Skip to content

Commit c467b3b

Browse files
author
Fabian Morgan
committed
ensure each S3 API has an associated S3 Action
1 parent 5665462 commit c467b3b

16 files changed

Lines changed: 599 additions & 132 deletions

File tree

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/S3Auth.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public class S3Auth {
2929
private String userPrincipal;
3030
// Optional STS session token when using temporary credentials
3131
private String sessionToken;
32+
// S3 action without s3: prefix (e.g. PutObject), set by S3 Gateway for use in finer-grained STS permissions.
33+
private String s3Action;
3234

3335
public S3Auth(final String stringToSign,
3436
final String signature,
@@ -67,4 +69,12 @@ public String getSessionToken() {
6769
public void setSessionToken(String sessionToken) {
6870
this.sessionToken = sessionToken;
6971
}
72+
73+
public String getS3Action() {
74+
return s3Action;
75+
}
76+
77+
public void setS3Action(String s3Action) {
78+
this.s3Action = s3Action;
79+
}
7080
}

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ private OMResponse submitRequest(OMRequest omRequest)
332332
if (threadLocalS3Auth.get().getSessionToken() != null) {
333333
s3AuthBuilder.setSessionToken(threadLocalS3Auth.get().getSessionToken());
334334
}
335+
if (threadLocalS3Auth.get().getS3Action() != null) {
336+
s3AuthBuilder.setS3Action(threadLocalS3Auth.get().getS3Action());
337+
}
335338

336339
builder.setS3Authentication(s3AuthBuilder.build());
337340
}
@@ -1788,10 +1791,7 @@ public OmMultipartCommitUploadPartInfo commitMultipartUploadPart(
17881791
handleError(submitRequest(omRequest))
17891792
.getCommitMultiPartUploadResponse();
17901793

1791-
OmMultipartCommitUploadPartInfo info = new
1792-
OmMultipartCommitUploadPartInfo(response.getPartName(),
1793-
response.getETag());
1794-
return info;
1794+
return new OmMultipartCommitUploadPartInfo(response.getPartName(), response.getETag());
17951795
}
17961796

17971797
@Override

hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1585,7 +1585,6 @@ message CommitKeyRequest {
15851585
}
15861586

15871587
message CommitKeyResponse {
1588-
15891588
}
15901589

15911590
message AllocateBlockRequest {
@@ -2346,6 +2345,9 @@ message S3Authentication {
23462345
optional string resolvedStsOriginalAccessKeyId = 7;
23472346
optional string resolvedStsTempAccessKeyId = 8;
23482347
optional string resolvedStsSecretKeyId = 9;
2348+
// S3 action without the s3: prefix for this request (e.g. GetObject), set by S3 Gateway for use
2349+
// in finer-grained STS permissions.
2350+
optional string s3Action = 10;
23492351
}
23502352

23512353
message RecoverLeaseRequest {

hadoop-ozone/interface-client/src/main/resources/proto.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8656,4 +8656,4 @@
86568656
}
86578657
}
86588658
]
8659-
}
8659+
}

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataReader.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatusLight;
5656
import org.apache.hadoop.ozone.om.helpers.S3VolumeContext;
5757
import org.apache.hadoop.ozone.om.protocolPB.grpc.GrpcClientConstants;
58+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Authentication;
5859
import org.apache.hadoop.ozone.security.STSTokenIdentifier;
5960
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
6061
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
@@ -236,9 +237,7 @@ public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
236237
try {
237238
if (isAclEnabled) {
238239
if (isStsS3Request()) {
239-
// We need to be able to tell the difference between being able to download a file and merely seeing the file
240-
// name in a list. Use READ for download ability and LIST (here) for listing.
241-
// When listPrefix is set (original S3 ListObjects prefix), authorize LIST on that prefix for the whole
240+
// When listPrefix is set (original S3 ListObjects prefix), authorize READ on that prefix for the whole
242241
// listing, including FSO traversal where keyName is an internal directory (e.g. userA) under prefix user.
243242
final String listPrefix = args.getListPrefix();
244243
final String keyName = args.getKeyName();
@@ -258,7 +257,7 @@ public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
258257
} else {
259258
aclKey = "*";
260259
}
261-
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.LIST, bucket.realVolume(), bucket.realBucket(), aclKey);
260+
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.READ, bucket.realVolume(), bucket.realBucket(), aclKey);
262261
} else {
263262
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.READ,
264263
bucket, args.getKeyName());
@@ -304,12 +303,7 @@ public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {
304303

305304
try {
306305
if (isAclEnabled) {
307-
if (isStsS3Request()) {
308-
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.LIST, bucket, args.getKeyName());
309-
} else {
310-
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.READ,
311-
bucket, args.getKeyName());
312-
}
306+
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.READ, bucket, args.getKeyName());
313307
}
314308
metrics.incNumGetFileStatus();
315309
return keyManager.getFileStatus(args, getClientAddress());
@@ -384,7 +378,7 @@ public ListKeysResult listKeys(String volumeName, String bucketName,
384378
final String aclKey = (keyPrefix == null || keyPrefix.isEmpty()) ? "*" : keyPrefix;
385379
captureLatencyNs(
386380
perfMetrics.getListKeysAclCheckLatencyNs(), () -> checkAcls(
387-
ResourceType.KEY, StoreType.OZONE, ACLType.LIST, bucket.realVolume(), bucket.realBucket(), aclKey));
381+
ResourceType.KEY, StoreType.OZONE, ACLType.READ, bucket.realVolume(), bucket.realBucket(), aclKey));
388382
} else {
389383
captureLatencyNs(perfMetrics.getListKeysAclCheckLatencyNs(), () ->
390384
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.LIST,
@@ -634,7 +628,8 @@ public boolean checkAcls(ResourceType resType, StoreType storeType,
634628
public boolean checkAcls(OzoneObj obj, RequestContext context,
635629
boolean throwIfPermissionDenied) throws OMException {
636630

637-
final RequestContext normalizedRequestContext = maybeAttachSessionPolicyFromThreadLocal(context);
631+
final RequestContext normalizedRequestContext = maybeAttachS3ActionFromThreadLocal(
632+
maybeAttachSessionPolicyFromThreadLocal(context));
638633

639634
if (!captureLatencyNs(perfMetrics::setCheckAccessLatencyNs,
640635
() -> accessAuthorizer.checkAccess(obj, normalizedRequestContext))) {
@@ -692,6 +687,22 @@ private RequestContext maybeAttachSessionPolicyFromThreadLocal(RequestContext co
692687
.build();
693688
}
694689

690+
/**
691+
* Attaches s3 action to RequestContext if an S3Authentication is found in the Ozone Manager thread local,
692+
* and it has an s3 action. Otherwise, returns the RequestContext as it was before.
693+
* @param context the original RequestContext
694+
* @return RequestContext as before or with s3 action embedded
695+
*/
696+
private RequestContext maybeAttachS3ActionFromThreadLocal(RequestContext context) {
697+
final S3Authentication s3Authentication = OzoneManager.getS3Auth();
698+
if (s3Authentication == null || !s3Authentication.hasS3Action()) {
699+
return context;
700+
}
701+
return context.toBuilder()
702+
.setS3Action(s3Authentication.getS3Action())
703+
.build();
704+
}
705+
695706
static String getClientAddress() {
696707
String clientMachine = Server.getRemoteAddress();
697708
if (clientMachine == null) { //not a RPC client

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/OzoneManagerStateMachine.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ public void close() {
664664
*/
665665
@VisibleForTesting
666666
OMResponse runCommand(OMRequest request, TermIndex termIndex) {
667+
boolean isS3AuthThreadLocalSet = false;
667668
boolean isStsThreadLocalSet = false;
668669
try {
669670
if (ozoneManager.isSecurityEnabled() && request.hasS3Authentication()) {
@@ -672,6 +673,10 @@ OMResponse runCommand(OMRequest request, TermIndex termIndex) {
672673
STSSecurityUtil.ensureResolvedStsFieldsInvariants(request);
673674

674675
final OzoneManagerProtocolProtos.S3Authentication s3Auth = request.getS3Authentication();
676+
// ThreadLocal carries S3 action for OmMetadataReader.
677+
OzoneManager.setS3Auth(s3Auth);
678+
isS3AuthThreadLocalSet = true;
679+
675680
if (s3Auth.hasSessionToken() && !s3Auth.getSessionToken().isEmpty()) {
676681
// ThreadLocal carries session policy for OmMetadataReader
677682
final STSTokenIdentifier rehydratedTokenIdentifier = new STSTokenIdentifier(
@@ -706,6 +711,9 @@ OMResponse runCommand(OMRequest request, TermIndex termIndex) {
706711
String errorMessage = "Request " + request + " failed with exception";
707712
ExitUtils.terminate(1, errorMessage, e, LOG);
708713
} finally {
714+
if (isS3AuthThreadLocalSet) {
715+
OzoneManager.setS3Auth(null);
716+
}
709717
if (isStsThreadLocalSet) {
710718
OzoneManager.setStsTokenIdentifier(null);
711719
}

0 commit comments

Comments
 (0)