Skip to content

Commit 312902c

Browse files
SophieGuo410Sophie Guo
andauthored
Adding signed url decoding logic in deleteHandler (#3155)
Co-authored-by: Sophie Guo <[email protected]>
1 parent a311be4 commit 312902c

File tree

8 files changed

+77
-8
lines changed

8 files changed

+77
-8
lines changed

ambry-frontend/src/main/java/com/github/ambry/frontend/DeleteBlobHandler.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.github.ambry.clustermap.ClusterMap;
2323
import com.github.ambry.commons.BlobId;
2424
import com.github.ambry.commons.Callback;
25-
import com.github.ambry.named.NamedBlobRecord;
2625
import com.github.ambry.quota.QuotaManager;
2726
import com.github.ambry.quota.QuotaUtils;
2827
import com.github.ambry.rest.RequestPath;
@@ -35,7 +34,10 @@
3534
import com.github.ambry.rest.RestServiceException;
3635
import com.github.ambry.rest.RestUtils;
3736
import com.github.ambry.router.Router;
37+
import com.github.ambry.utils.Pair;
38+
import java.io.IOException;
3839
import java.util.GregorianCalendar;
40+
import java.util.Map;
3941
import org.slf4j.Logger;
4042
import org.slf4j.LoggerFactory;
4143

@@ -60,10 +62,11 @@ public class DeleteBlobHandler {
6062
private final ClusterMap clusterMap;
6163
private final QuotaManager quotaManager;
6264
private final AccountService accountService;
65+
private final IdSigningService idSigningService;
6366

6467
DeleteBlobHandler(Router router, SecurityService securityService, IdConverter idConverter,
6568
AccountAndContainerInjector accountAndContainerInjector, FrontendMetrics metrics, ClusterMap clusterMap,
66-
QuotaManager quotaManager, AccountService accountService) {
69+
QuotaManager quotaManager, AccountService accountService, IdSigningService idSigningService) {
6770
this.router = router;
6871
this.securityService = securityService;
6972
this.idConverter = idConverter;
@@ -72,6 +75,7 @@ public class DeleteBlobHandler {
7275
this.clusterMap = clusterMap;
7376
this.quotaManager = quotaManager;
7477
this.accountService = accountService;
78+
this.idSigningService = idSigningService;
7579
}
7680

7781
public void handle(RestRequest restRequest, RestResponseChannel restResponseChannel, Callback<Void> callback)
@@ -122,7 +126,9 @@ private Callback<Void> securityProcessRequestCallback() {
122126
String blobIdStr = getRequestPath(restRequest).getOperationOrBlobId(false);
123127
if (restRequest.getArgs().get(InternalKeys.TARGET_ACCOUNT_KEY) == null) {
124128
// Inject account and container when they are missing from the rest request.
125-
blobIdStr = RestUtils.stripSlashAndExtensionFromId(blobIdStr);
129+
String decryptedInput =
130+
parseSignedIdIfRequired(blobIdStr.startsWith("/") ? blobIdStr.substring(1) : blobIdStr);
131+
blobIdStr = RestUtils.stripSlashAndExtensionFromId(decryptedInput);
126132
BlobId convertedBlobId = FrontendUtils.getBlobIdFromString(blobIdStr, clusterMap);
127133
accountAndContainerInjector.injectTargetAccountAndContainerFromBlobId(convertedBlobId, restRequest,
128134
metrics.deleteBlobMetricsGroup);
@@ -242,5 +248,18 @@ private void deleteDatasetVersion(RestRequest restRequest) throws RestServiceExc
242248
RestServiceErrorCode.getRestServiceErrorCode(ex.getErrorCode()));
243249
}
244250
}
251+
252+
private String parseSignedIdIfRequired(String incomingId) throws RestServiceException {
253+
String blobId;
254+
String sanitizedIncomingId = stripSlashAndExtensionFromId(incomingId);
255+
if (idSigningService.isIdSigned(sanitizedIncomingId)) {
256+
Pair<String, Map<String, String>> idAndMetadata = idSigningService.parseSignedId(sanitizedIncomingId);
257+
restRequest.setArg(RestUtils.InternalKeys.SIGNED_ID_METADATA_KEY, idAndMetadata.getSecond());
258+
blobId = conditionalCopySlashAndExtension(incomingId, idAndMetadata.getFirst());
259+
} else {
260+
blobId = incomingId;
261+
}
262+
return blobId;
263+
}
245264
}
246265
}

ambry-frontend/src/main/java/com/github/ambry/frontend/FrontendRestRequestService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public void start() throws InstantiationException {
211211
new CopyDatasetVersionHandler(securityService, accountService, frontendMetrics, accountAndContainerInjector);
212212
deleteBlobHandler =
213213
new DeleteBlobHandler(router, securityService, idConverter, accountAndContainerInjector, frontendMetrics,
214-
clusterMap, quotaManager, accountService);
214+
clusterMap, quotaManager, accountService, idSigningService);
215215
deleteDatasetHandler =
216216
new DeleteDatasetHandler(securityService, accountService, frontendMetrics, accountAndContainerInjector,
217217
deleteBlobHandler);

ambry-frontend/src/main/java/com/github/ambry/frontend/FrontendUtils.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,42 @@ static BlobId getBlobIdFromString(String blobIdStr, ClusterMap clusterMap) throw
8484
}
8585
}
8686

87+
/**
88+
* Copies leading slash and/or extension from {@code src} to {@code dest} if present in {@code src} and not present
89+
* in {@code dest}
90+
* <p/>
91+
* Does not overwrite if already present in {@code dest}. Does not create if not present in {@code src}.
92+
* @param src the source string
93+
* @param dest the destination string
94+
* @return {@code dest} with leading slash and/or extension (depending on presence in {@code src} and {@code dest}).
95+
*/
96+
public static String conditionalCopySlashAndExtension(String src, String dest) {
97+
if (src.startsWith("/")) {
98+
dest = addLeadingSlashIfAbsent(dest);
99+
}
100+
int destExtensionIndex = dest.indexOf(".");
101+
if (destExtensionIndex == -1) {
102+
int srcExtensionIndex = src.indexOf(".");
103+
if (srcExtensionIndex != -1) {
104+
String extension = src.substring(srcExtensionIndex);
105+
dest = dest + extension;
106+
}
107+
}
108+
return dest;
109+
}
110+
111+
/**
112+
* Adds a leading slash if {@code input} doesn't already have one.
113+
* @param input the input string
114+
* @return input string with a leading slash.
115+
*/
116+
public static String addLeadingSlashIfAbsent(String input) {
117+
if (!input.startsWith("/")) {
118+
return "/" + input;
119+
}
120+
return input;
121+
}
122+
87123
/**
88124
* @param metrics the {@link AsyncOperationTracker.Metrics} instance to update.
89125
* @param successAction the action to take if the callback was called successfully.

ambry-frontend/src/test/java/com/github/ambry/frontend/NamedBlobDeleteHandlerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public NamedBlobDeleteHandlerTest() throws Exception {
138138
ACCOUNT_SERVICE, null);
139139
deleteBlobHandler =
140140
new DeleteBlobHandler(router, securityServiceFactory.getSecurityService(), idConverterFactory.getIdConverter(),
141-
injector, metrics, CLUSTER_MAP, QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE);
141+
injector, metrics, CLUSTER_MAP, QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE, null);
142142
}
143143

144144
@Test

ambry-frontend/src/test/java/com/github/ambry/frontend/PostBlobHandlerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import java.nio.charset.StandardCharsets;
6868
import java.util.ArrayList;
6969
import java.util.Arrays;
70+
import java.util.Base64;
7071
import java.util.Collections;
7172
import java.util.HashMap;
7273
import java.util.LinkedList;
@@ -78,6 +79,7 @@
7879
import java.util.concurrent.TimeUnit;
7980
import java.util.stream.Collectors;
8081
import java.util.stream.Stream;
82+
import org.apache.commons.lang3.tuple.Pair;
8183
import org.json.JSONObject;
8284
import org.junit.Test;
8385
import org.junit.runner.RunWith;
@@ -87,6 +89,7 @@
8789
import static com.github.ambry.frontend.FrontendRestRequestServiceTest.*;
8890
import static com.github.ambry.rest.RestUtils.InternalKeys.*;
8991
import static org.junit.Assert.*;
92+
import static org.mockito.Mockito.*;
9093

9194

9295
/**
@@ -146,6 +149,7 @@ public class PostBlobHandlerTest {
146149
private FrontendConfig frontendConfig;
147150
private PostBlobHandler postBlobHandler;
148151
private GetBlobHandler getBlobHandler;
152+
private DeleteBlobHandler deleteBlobHandler;
149153

150154
private String reservedMetadataId;
151155

@@ -170,6 +174,7 @@ public PostBlobHandlerTest(boolean isReservedMetadataEnabled) {
170174
}
171175
initPostBlobHandler(props);
172176
initGetBlobHandler(props);
177+
initDeleteBlobHandler(props);
173178
}
174179

175180
/**
@@ -399,6 +404,14 @@ private void initGetBlobHandler(Properties properties) {
399404
idConverterFactory.getIdConverter(), injector, metrics, CLUSTER_MAP, QUOTA_MANAGER, ACCOUNT_SERVICE);
400405
}
401406

407+
private void initDeleteBlobHandler(Properties props) {
408+
VerifiableProperties verifiableProperties = new VerifiableProperties(props);
409+
frontendConfig = new FrontendConfig(verifiableProperties);
410+
deleteBlobHandler =
411+
new DeleteBlobHandler(router, securityServiceFactory.getSecurityService(), idConverterFactory.getIdConverter(),
412+
injector, metrics, CLUSTER_MAP, QUOTA_MANAGER, ACCOUNT_SERVICE, idSigningService);
413+
}
414+
402415
// ttlRequiredEnforcementTest() helpers
403416

404417
/**

ambry-frontend/src/test/java/com/github/ambry/frontend/S3BatchDeleteHandlerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ private void setup() throws Exception {
248248
QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE, null);
249249
DeleteBlobHandler deleteBlobHandler =
250250
new DeleteBlobHandler(router, securityService, ambryIdConverterFactory.getIdConverter(), injector, metrics,
251-
new MockClusterMap(), QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE);
251+
new MockClusterMap(), QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE, null);
252252
s3BatchDeleteHandler = new S3BatchDeleteHandler(deleteBlobHandler, metrics);
253253
}
254254

ambry-frontend/src/test/java/com/github/ambry/frontend/S3DeleteHandlerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ private void setup() throws Exception {
134134
QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE, null);
135135
DeleteBlobHandler deleteBlobHandler =
136136
new DeleteBlobHandler(router, securityService, ambryIdConverterFactory.getIdConverter(), injector, metrics,
137-
new MockClusterMap(), QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE);
137+
new MockClusterMap(), QuotaTestUtils.createDummyQuotaManager(), ACCOUNT_SERVICE, null);
138138
s3DeleteHandler = new S3DeleteHandler(deleteBlobHandler, null, metrics);
139139
}
140140

ambry-frontend/src/test/java/com/github/ambry/frontend/S3MultipartUploadTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,8 @@ private void setup() throws Exception {
361361
new GetBlobHandler(frontendConfig, router, securityService, idConverter, injector, metrics, clusterMap,
362362
quotaManager, ACCOUNT_SERVICE);
363363
deleteBlobHandler =
364-
new DeleteBlobHandler(router, securityService, idConverter, injector, metrics, clusterMap, quotaManager, ACCOUNT_SERVICE);
364+
new DeleteBlobHandler(router, securityService, idConverter, injector, metrics, clusterMap, quotaManager, ACCOUNT_SERVICE,
365+
null);
365366
s3MultipartUploadHandler = new S3MultipartUploadHandler(securityService, metrics, injector, frontendConfig,
366367
namedBlobDb, idConverter, router, quotaManager);
367368

0 commit comments

Comments
 (0)