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
22namespace 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