Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,16 @@ public static Builder newBuilder() {
return new Builder();
}

public static Builder getBuilder(ResourceType resType,
StoreType storeType, String vol, String bucket, String key) {
return OzoneObjInfo.Builder.newBuilder()
.setResType(resType)
.setStoreType(storeType)
.setVolumeName(vol)
.setBucketName(bucket)
.setKeyName(key);
}

public static Builder fromKeyArgs(OmKeyArgs args) {
return new Builder()
.setVolumeName(args.getVolumeName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.apache.hadoop.ozone.security.acl;

import org.apache.hadoop.ipc.ProtobufRpcEngine;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
Expand All @@ -32,16 +33,20 @@ public class RequestContext {
private final String serviceId;
private final ACLIdentityType aclType;
private final ACLType aclRights;
private final String ownerName;

@SuppressWarnings("parameternumber")
public RequestContext(String host, InetAddress ip,
UserGroupInformation clientUgi, String serviceId,
ACLIdentityType aclType, ACLType aclRights) {
ACLIdentityType aclType, ACLType aclRights,
String ownerName) {
this.host = host;
this.ip = ip;
this.clientUgi = clientUgi;
this.serviceId = serviceId;
this.aclType = aclType;
this.aclRights = aclRights;
this.ownerName = ownerName;
}

/**
Expand All @@ -55,6 +60,12 @@ public static class Builder {
private IAccessAuthorizer.ACLIdentityType aclType;
private IAccessAuthorizer.ACLType aclRights;

/**
* ownerName is specially added to allow
* authorizer to honor owner privilege.
*/
private String ownerName;

public Builder setHost(String bHost) {
this.host = bHost;
return this;
Expand All @@ -80,21 +91,51 @@ public Builder setAclType(ACLIdentityType acl) {
return this;
}

public ACLType getAclRights() {
return this.aclRights;
}

public Builder setAclRights(ACLType aclRight) {
this.aclRights = aclRight;
return this;
}

public Builder setOwnerName(String owner) {
this.ownerName = owner;
return this;
}

public RequestContext build() {
return new RequestContext(host, ip, clientUgi, serviceId, aclType,
aclRights);
aclRights, ownerName);
}
}

public static Builder newBuilder() {
return new Builder();
}

public static RequestContext.Builder getBuilder(
UserGroupInformation ugi, InetAddress remoteAddress, String hostName,
ACLType aclType, String ownerName) {
RequestContext.Builder contextBuilder = RequestContext.newBuilder()
.setClientUgi(ugi)
.setIp(remoteAddress)
.setHost(hostName)
.setAclType(ACLIdentityType.USER)
.setAclRights(aclType)
.setOwnerName(ownerName);
return contextBuilder;
}

public static RequestContext.Builder getBuilder(UserGroupInformation ugi,
ACLType aclType, String ownerName) {
return getBuilder(ugi,
ProtobufRpcEngine.Server.getRemoteIp(),
ProtobufRpcEngine.Server.getRemoteIp().getHostName(),
aclType, ownerName);
}

public String getHost() {
return host;
}
Expand All @@ -119,4 +160,7 @@ public ACLType getAclRights() {
return aclRights;
}

public String getOwnerName() {
return ownerName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,14 @@ public void testBucketCreationPermissionDenied() throws Exception {

String volumeName = RandomStringUtils.randomAlphabetic(5).toLowerCase();
String bucketName = RandomStringUtils.randomAlphabetic(5).toLowerCase();
cluster.getClient().getObjectStore().createVolume(volumeName);

VolumeArgs createVolumeArgs = VolumeArgs.newBuilder()
.setOwner("user" + RandomStringUtils.randomNumeric(5))
.setAdmin("admin" + RandomStringUtils.randomNumeric(5))
.build();

cluster.getClient().getObjectStore().createVolume(volumeName,
createVolumeArgs);
OzoneVolume volume =
cluster.getClient().getObjectStore().getVolume(volumeName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,16 @@ public void testListVolumeWithOtherUsersListAllAllowed() throws Exception {

// Login as user1, list other users' volumes
UserGroupInformation.setLoginUser(user1);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume5"),
true);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume4",
"volume5"), true);

// Add "s3v" created default by OM.
checkUser(cluster, adminUser, Arrays.asList("volume1", "volume2", "volume3",
"volume4", "volume5", "s3v"), true);

UserGroupInformation.setLoginUser(user2);
checkUser(cluster, user1, Arrays.asList("volume1", "volume4", "volume5"),
true);
checkUser(cluster, user1, Arrays.asList("volume1", "volume3", "volume4",
"volume5"), true);
checkUser(cluster, adminUser, Arrays.asList("volume1", "volume2", "volume3",
"volume4", "volume5", "s3v"), true);

Expand All @@ -229,18 +229,18 @@ public void testListVolumeWithOtherUsersListAllDisallowed() throws Exception {

// Login as user1, list other users' volumes, expect failure
UserGroupInformation.setLoginUser(user1);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume5"),
false);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume4",
"volume5"), false);
// Add "s3v" created default by OM.
checkUser(cluster, adminUser, Arrays.asList("volume1", "volume2", "volume3",
"volume4", "volume5", "s3v"), false);

// While admin should be able to list volumes just fine.
UserGroupInformation.setLoginUser(adminUser);
checkUser(cluster, user1, Arrays.asList("volume1", "volume4", "volume5"),
true);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume5"),
true);
checkUser(cluster, user1, Arrays.asList("volume1", "volume3", "volume4",
"volume5"), true);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume4",
"volume5"), true);

stopCluster(cluster);
}
Expand All @@ -249,10 +249,10 @@ public void testListVolumeWithOtherUsersListAllDisallowed() throws Exception {
public void testAclEnabledListAllAllowed() throws Exception {
// ozone.acl.enabled = true, ozone.om.volume.listall.allowed = true
MiniOzoneCluster cluster = startCluster(true, true);
checkUser(cluster, user1, Arrays.asList("volume1", "volume4", "volume5"),
true);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume5"),
true);
checkUser(cluster, user1, Arrays.asList("volume1", "volume3", "volume4",
"volume5"), true);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume4",
"volume5"), true);

// Add "s3v" created default by OM.
checkUser(cluster, adminUser, Arrays.asList("volume1", "volume2", "volume3",
Expand All @@ -267,11 +267,11 @@ public void testAclEnabledListAllDisallowed() throws Exception {
// The default user is adminUser as set in init(),
// listall always succeeds if we use that UGI, we should use non-admin here
UserGroupInformation.setLoginUser(user1);
checkUser(cluster, user1, Arrays.asList("volume1", "volume4", "volume5"),
false);
checkUser(cluster, user1, Arrays.asList("volume1", "volume3", "volume4",
"volume5"), false);
UserGroupInformation.setLoginUser(user2);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume5"),
false);
checkUser(cluster, user2, Arrays.asList("volume2", "volume3", "volume4",
"volume5"), false);
UserGroupInformation.setLoginUser(adminUser);
// Add "s3v" created default by OM.
checkUser(cluster, adminUser, Arrays.asList("volume1", "volume2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_ERROR_OTHER;
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneManagerService.newReflectiveBlockingService;

import org.apache.hadoop.util.Time;
Expand Down Expand Up @@ -528,6 +529,7 @@ private void instantiateServices() throws IOException {
authorizer.setKeyManager(keyManager);
authorizer.setPrefixManager(prefixManager);
authorizer.setOzoneAdmins(getOzoneAdmins(configuration));
authorizer.setAllowListAllVolumes(allowListAllVolumes);
}
} else {
accessAuthorizer = null;
Expand Down Expand Up @@ -1627,7 +1629,7 @@ private void checkAcls(ResourceType resType, StoreType store,
ProtobufRpcEngine.Server.getRemoteUser(),
ProtobufRpcEngine.Server.getRemoteIp(),
ProtobufRpcEngine.Server.getRemoteIp().getHostName(),
true);
true, getVolumeOwner(vol, acl));
}

/**
Expand All @@ -1642,25 +1644,46 @@ private boolean hasAcls(String userName, ResourceType resType,
UserGroupInformation.createRemoteUser(userName),
ProtobufRpcEngine.Server.getRemoteIp(),
ProtobufRpcEngine.Server.getRemoteIp().getHostName(),
false);
false, getVolumeOwner(vol, acl));
} catch (OMException ex) {
// Should not trigger exception here at all
return false;
}
}

/**
* CheckAcls for the ozone object.
*
* @throws OMException ResultCodes.PERMISSION_DENIED if permission denied.
*/
@SuppressWarnings("parameternumber")
public void checkAcls(ResourceType resType, StoreType storeType,
ACLType aclType, String vol, String bucket, String key,
UserGroupInformation ugi, InetAddress remoteAddress, String hostName)
throws OMException {
checkAcls(resType, storeType, aclType, vol, bucket, key,
ugi, remoteAddress, hostName, true);
public String getVolumeOwner(String vol, ACLType type) throws OMException {
String volOwnerName = null;
if (!vol.equals(OzoneConsts.OZONE_ROOT) && (type != ACLType.CREATE)) {
volOwnerName = getVolumeOwner(vol);
}
return volOwnerName;
}

private String getVolumeOwner(String volume) throws OMException {
Boolean lockAcquired = metadataManager.getLock().acquireReadLock(
VOLUME_LOCK, volume);
String dbVolumeKey = metadataManager.getVolumeKey(volume);
OmVolumeArgs volumeArgs = null;
try {
volumeArgs = metadataManager.getVolumeTable().get(dbVolumeKey);
} catch (IOException ioe) {
if (ioe instanceof OMException) {
throw (OMException)ioe;
} else {
throw new OMException("getVolumeOwner for Volume " + volume + " failed",
ResultCodes.INTERNAL_ERROR);
}
} finally {
if (lockAcquired) {
metadataManager.getLock().releaseReadLock(VOLUME_LOCK, volume);
}
}
if (volumeArgs != null) {
return volumeArgs.getOwnerName();
} else {
throw new OMException("Volume " + volume + " is not found",
OMException.ResultCodes.VOLUME_NOT_FOUND);
}
}

/**
Expand All @@ -1671,10 +1694,10 @@ public void checkAcls(ResourceType resType, StoreType storeType,
* and throwOnPermissionDenied set to true.
*/
@SuppressWarnings("parameternumber")
private boolean checkAcls(ResourceType resType, StoreType storeType,
public boolean checkAcls(ResourceType resType, StoreType storeType,
ACLType aclType, String vol, String bucket, String key,
UserGroupInformation ugi, InetAddress remoteAddress, String hostName,
boolean throwIfPermissionDenied)
boolean throwIfPermissionDenied, String volumeOwner)
throws OMException {
OzoneObj obj = OzoneObjInfo.Builder.newBuilder()
.setResType(resType)
Expand All @@ -1688,13 +1711,17 @@ private boolean checkAcls(ResourceType resType, StoreType storeType,
.setHost(hostName)
.setAclType(ACLIdentityType.USER)
.setAclRights(aclType)
.setOwnerName(volumeOwner)
.build();
if (!accessAuthorizer.checkAccess(obj, context)) {
if (throwIfPermissionDenied) {
LOG.warn("User {} doesn't have {} permission to access {} /{}/{}/{}",
ugi.getUserName(), aclType, resType, vol, bucket, key);
throw new OMException("User " + ugi.getUserName() + " doesn't have " +
aclType + " permission to access " + resType,
context.getClientUgi().getUserName(), context.getAclRights(),
obj.getResourceType(), obj.getVolumeName(), obj.getBucketName(),
obj.getKeyName());
throw new OMException("User " + context.getClientUgi().getUserName() +
" doesn't have " + context.getAclRights() +
" permission to access " + obj.getResourceType(),
ResultCodes.PERMISSION_DENIED);
}
return false;
Expand Down Expand Up @@ -3497,7 +3524,6 @@ public ResolvedBucket resolveBucketLink(Pair<String, String> requested,
return new ResolvedBucket(requested, resolved);
}


public ResolvedBucket resolveBucketLink(Pair<String, String> requested)
throws IOException {

Expand Down Expand Up @@ -3548,9 +3574,11 @@ private Pair<String, String> resolveBucketLink(
}

if (isAclEnabled) {
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.READ,
final ACLType type = ACLType.READ;
checkAcls(ResourceType.BUCKET, StoreType.OZONE, type,
volumeName, bucketName, null, userGroupInformation,
remoteAddress, hostName);
remoteAddress, hostName, true,
getVolumeOwner(volumeName, type));
}

return resolveBucketLink(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,36 @@ public OzoneManagerProtocolProtos.UserInfo getUserInfo() {
* @param key
* @throws IOException
*/
@SuppressWarnings("parameternumber")
public void checkAcls(OzoneManager ozoneManager,
OzoneObj.ResourceType resType,
OzoneObj.StoreType storeType, IAccessAuthorizer.ACLType aclType,
String vol, String bucket, String key) throws IOException {
checkAcls(ozoneManager, resType, storeType, aclType, vol, bucket, key,
ozoneManager.getVolumeOwner(vol, aclType));
}

/**
* Check Acls of ozone object with volOwner given.
* @param ozoneManager
* @param resType
* @param storeType
* @param aclType
* @param vol
* @param bucket
* @param key
* @param volOwner
* @throws IOException
*/
@SuppressWarnings("parameternumber")
public void checkAcls(OzoneManager ozoneManager,
OzoneObj.ResourceType resType,
OzoneObj.StoreType storeType, IAccessAuthorizer.ACLType aclType,
String vol, String bucket, String key, String volOwner)
throws IOException {
ozoneManager.checkAcls(resType, storeType, aclType, vol, bucket, key,
createUGI(), getRemoteAddress(), getHostName());
createUGI(), getRemoteAddress(), getHostName(), true,
volOwner);
}

/**
Expand Down
Loading