HDDS-1611. Evaluate ACL on volume bucket key and prefix to authorize access. Contributed by Ajay Kumar. (#973)
This commit is contained in:
parent
90b10a0d54
commit
cdb20adfcc
|
@ -120,6 +120,10 @@ public final class OzoneConfigKeys {
|
||||||
* */
|
* */
|
||||||
public static final String OZONE_ADMINISTRATORS =
|
public static final String OZONE_ADMINISTRATORS =
|
||||||
"ozone.administrators";
|
"ozone.administrators";
|
||||||
|
/**
|
||||||
|
* Used only for testing purpose. Results in making every user an admin.
|
||||||
|
* */
|
||||||
|
public static final String OZONE_ADMINISTRATORS_WILDCARD = "*";
|
||||||
|
|
||||||
public static final String OZONE_CLIENT_PROTOCOL =
|
public static final String OZONE_CLIENT_PROTOCOL =
|
||||||
"ozone.client.protocol";
|
"ozone.client.protocol";
|
||||||
|
@ -390,6 +394,8 @@ public final class OzoneConfigKeys {
|
||||||
"ozone.acl.authorizer.class";
|
"ozone.acl.authorizer.class";
|
||||||
public static final String OZONE_ACL_AUTHORIZER_CLASS_DEFAULT =
|
public static final String OZONE_ACL_AUTHORIZER_CLASS_DEFAULT =
|
||||||
"org.apache.hadoop.ozone.security.acl.OzoneAccessAuthorizer";
|
"org.apache.hadoop.ozone.security.acl.OzoneAccessAuthorizer";
|
||||||
|
public static final String OZONE_ACL_AUTHORIZER_CLASS_NATIVE =
|
||||||
|
"org.apache.hadoop.ozone.security.acl.OzoneNativeAuthorizer";
|
||||||
public static final String OZONE_ACL_ENABLED =
|
public static final String OZONE_ACL_ENABLED =
|
||||||
"ozone.acl.enabled";
|
"ozone.acl.enabled";
|
||||||
public static final boolean OZONE_ACL_ENABLED_DEFAULT =
|
public static final boolean OZONE_ACL_ENABLED_DEFAULT =
|
||||||
|
|
|
@ -219,7 +219,6 @@ public class TestDiskBalancer {
|
||||||
} finally {
|
} finally {
|
||||||
cluster.shutdown();
|
cluster.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -892,6 +892,7 @@ public class RpcClient implements ClientProtocol {
|
||||||
.setBucketName(bucketName)
|
.setBucketName(bucketName)
|
||||||
.setKeyName(keyName)
|
.setKeyName(keyName)
|
||||||
.setMultipartUploadID(uploadID)
|
.setMultipartUploadID(uploadID)
|
||||||
|
.setAcls(getAclList())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
OmMultipartUploadList omMultipartUploadList = new OmMultipartUploadList(
|
OmMultipartUploadList omMultipartUploadList = new OmMultipartUploadList(
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
package org.apache.hadoop.ozone;
|
package org.apache.hadoop.ozone;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclRights;
|
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
||||||
|
@ -30,6 +30,7 @@ import java.util.ArrayList;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OzoneACL classes define bucket ACLs used in OZONE.
|
* OzoneACL classes define bucket ACLs used in OZONE.
|
||||||
|
@ -46,6 +47,7 @@ public class OzoneAcl {
|
||||||
private ACLIdentityType type;
|
private ACLIdentityType type;
|
||||||
private String name;
|
private String name;
|
||||||
private BitSet aclBitSet;
|
private BitSet aclBitSet;
|
||||||
|
private static final List<ACLType> EMPTY_LIST = new ArrayList<>(0);
|
||||||
public static final BitSet ZERO_BITSET = new BitSet(0);
|
public static final BitSet ZERO_BITSET = new BitSet(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,8 +68,16 @@ public class OzoneAcl {
|
||||||
this.aclBitSet = new BitSet(ACLType.getNoOfAcls());
|
this.aclBitSet = new BitSet(ACLType.getNoOfAcls());
|
||||||
aclBitSet.set(acl.ordinal(), true);
|
aclBitSet.set(acl.ordinal(), true);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
if (type == ACLIdentityType.WORLD && name.length() != 0) {
|
if (type == ACLIdentityType.WORLD || type == ACLIdentityType.ANONYMOUS) {
|
||||||
throw new IllegalArgumentException("Unexpected name part in world type");
|
if (!name.equals(ACLIdentityType.WORLD.name()) &&
|
||||||
|
!name.equals(ACLIdentityType.ANONYMOUS.name()) &&
|
||||||
|
name.length() != 0) {
|
||||||
|
throw new IllegalArgumentException("Unexpected name:{" + name +
|
||||||
|
"} for type WORLD, ANONYMOUS. It should be WORLD & " +
|
||||||
|
"ANONYMOUS respectively.");
|
||||||
|
}
|
||||||
|
// For type WORLD and ANONYMOUS we allow only one acl to be set.
|
||||||
|
this.name = type.name();
|
||||||
}
|
}
|
||||||
if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
|
if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
|
||||||
&& (name.length() == 0)) {
|
&& (name.length() == 0)) {
|
||||||
|
@ -91,14 +101,20 @@ public class OzoneAcl {
|
||||||
"size. bitset size:" + acls.cardinality() + ", bitset:"
|
"size. bitset size:" + acls.cardinality() + ", bitset:"
|
||||||
+ acls.toString());
|
+ acls.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.aclBitSet = (BitSet) acls.clone();
|
this.aclBitSet = (BitSet) acls.clone();
|
||||||
acls.stream().forEach(a -> aclBitSet.set(a));
|
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
if (type == ACLIdentityType.WORLD && name.length() != 0) {
|
if (type == ACLIdentityType.WORLD || type == ACLIdentityType.ANONYMOUS) {
|
||||||
throw new IllegalArgumentException("Unexpected name part in world type");
|
if (!name.equals(ACLIdentityType.WORLD.name()) &&
|
||||||
|
!name.equals(ACLIdentityType.ANONYMOUS.name()) &&
|
||||||
|
name.length() != 0) {
|
||||||
|
throw new IllegalArgumentException("Unexpected name:{" + name +
|
||||||
|
"} for type WORLD, ANONYMOUS. It should be WORLD & " +
|
||||||
|
"ANONYMOUS respectively.");
|
||||||
|
}
|
||||||
|
// For type WORLD and ANONYMOUS we allow only one acl to be set.
|
||||||
|
this.name = type.name();
|
||||||
}
|
}
|
||||||
if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
|
if (((type == ACLIdentityType.USER) || (type == ACLIdentityType.GROUP))
|
||||||
&& (name.length() == 0)) {
|
&& (name.length() == 0)) {
|
||||||
|
@ -161,17 +177,13 @@ public class OzoneAcl {
|
||||||
public static OzoneAclInfo toProtobuf(OzoneAcl acl) {
|
public static OzoneAclInfo toProtobuf(OzoneAcl acl) {
|
||||||
OzoneAclInfo.Builder builder = OzoneAclInfo.newBuilder()
|
OzoneAclInfo.Builder builder = OzoneAclInfo.newBuilder()
|
||||||
.setName(acl.getName())
|
.setName(acl.getName())
|
||||||
.setType(OzoneAclType.valueOf(acl.getType().name()));
|
.setType(OzoneAclType.valueOf(acl.getType().name()))
|
||||||
acl.getAclBitSet().stream().forEach(a ->
|
.setRights(ByteString.copyFrom(acl.getAclBitSet().toByteArray()));
|
||||||
builder.addRights(OzoneAclRights.valueOf(ACLType.values()[a].name())));
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OzoneAcl fromProtobuf(OzoneAclInfo protoAcl) {
|
public static OzoneAcl fromProtobuf(OzoneAclInfo protoAcl) {
|
||||||
BitSet aclRights = new BitSet(ACLType.getNoOfAcls());
|
BitSet aclRights = BitSet.valueOf(protoAcl.getRights().toByteArray());
|
||||||
protoAcl.getRightsList().parallelStream().forEach(a ->
|
|
||||||
aclRights.set(a.ordinal()));
|
|
||||||
|
|
||||||
return new OzoneAcl(ACLIdentityType.valueOf(protoAcl.getType().name()),
|
return new OzoneAcl(ACLIdentityType.valueOf(protoAcl.getType().name()),
|
||||||
protoAcl.getName(), aclRights);
|
protoAcl.getName(), aclRights);
|
||||||
}
|
}
|
||||||
|
@ -215,11 +227,11 @@ public class OzoneAcl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ACLType> getAclList() {
|
public List<ACLType> getAclList() {
|
||||||
List<ACLType> acls = new ArrayList<>(ACLType.getNoOfAcls());
|
|
||||||
if(aclBitSet != null) {
|
if(aclBitSet != null) {
|
||||||
aclBitSet.stream().forEach(a -> acls.add(ACLType.values()[a]));
|
return aclBitSet.stream().mapToObj(a ->
|
||||||
|
ACLType.values()[a]).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
return acls;
|
return EMPTY_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,15 +18,17 @@
|
||||||
|
|
||||||
package org.apache.hadoop.ozone.om.helpers;
|
package org.apache.hadoop.ozone.om.helpers;
|
||||||
|
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
import org.apache.hadoop.ozone.OzoneAcl;
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.protocol.proto
|
import org.apache.hadoop.ozone.protocol.proto
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo;
|
.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.protocol.proto
|
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclRights;
|
|
||||||
import org.apache.hadoop.ozone.protocol.proto
|
import org.apache.hadoop.ozone.protocol.proto
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -38,7 +40,8 @@ import java.util.Objects;
|
||||||
|
|
||||||
import static org.apache.hadoop.ozone.OzoneAcl.ZERO_BITSET;
|
import static org.apache.hadoop.ozone.OzoneAcl.ZERO_BITSET;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
|
||||||
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclRights.ALL;
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.NONE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This helper class keeps a map of all user and their permissions.
|
* This helper class keeps a map of all user and their permissions.
|
||||||
|
@ -92,7 +95,7 @@ public class OmOzoneAclMap {
|
||||||
throw new OMException("Acl " + acl + " already exist.",
|
throw new OMException("Acl " + acl + " already exist.",
|
||||||
INVALID_REQUEST);
|
INVALID_REQUEST);
|
||||||
}
|
}
|
||||||
getMap(aclType).get(acl.getName()).or(acl.getAclBitSet());
|
getMap(aclType).replace(acl.getName(), temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,8 +146,7 @@ public class OmOzoneAclMap {
|
||||||
public void addAcl(OzoneAclInfo acl) throws OMException {
|
public void addAcl(OzoneAclInfo acl) throws OMException {
|
||||||
Objects.requireNonNull(acl, "Acl should not be null.");
|
Objects.requireNonNull(acl, "Acl should not be null.");
|
||||||
if (!getMap(acl.getType()).containsKey(acl.getName())) {
|
if (!getMap(acl.getType()).containsKey(acl.getName())) {
|
||||||
BitSet acls = new BitSet(OzoneAclRights.values().length);
|
BitSet acls = BitSet.valueOf(acl.getRights().toByteArray());
|
||||||
acl.getRightsList().parallelStream().forEach(a -> acls.set(a.ordinal()));
|
|
||||||
getMap(acl.getType()).put(acl.getName(), acls);
|
getMap(acl.getType()).put(acl.getName(), acls);
|
||||||
} else {
|
} else {
|
||||||
// throw exception if acl is already added.
|
// throw exception if acl is already added.
|
||||||
|
@ -163,12 +165,67 @@ public class OmOzoneAclMap {
|
||||||
if (aclBitSet == null) {
|
if (aclBitSet == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
BitSet result = BitSet.valueOf(acl.getRights().toByteArray());
|
||||||
|
result.and(aclBitSet);
|
||||||
|
return (!result.equals(ZERO_BITSET) || aclBitSet.get(ALL.ordinal()))
|
||||||
|
&& !aclBitSet.get(NONE.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
for (OzoneAclRights right : acl.getRightsList()) {
|
/**
|
||||||
if (aclBitSet.get(right.ordinal()) || aclBitSet.get(ALL.ordinal())) {
|
* For a given acl, check if the user has access rights.
|
||||||
|
* Acl's are checked in followoing order:
|
||||||
|
* 1. Acls for USER.
|
||||||
|
* 2. Acls for GROUPS.
|
||||||
|
* 3. Acls for WORLD.
|
||||||
|
* 4. Acls for ANONYMOUS.
|
||||||
|
* @param acl
|
||||||
|
* @param ugi
|
||||||
|
*
|
||||||
|
* @return true if given ugi has acl set, else false.
|
||||||
|
* */
|
||||||
|
public boolean hasAccess(ACLType acl, UserGroupInformation ugi) {
|
||||||
|
if (acl == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ugi == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check acls in user acl list.
|
||||||
|
return checkAccessForOzoneAclType(OzoneAclType.USER, acl, ugi)
|
||||||
|
|| checkAccessForOzoneAclType(OzoneAclType.GROUP, acl, ugi)
|
||||||
|
|| checkAccessForOzoneAclType(OzoneAclType.WORLD, acl, ugi)
|
||||||
|
|| checkAccessForOzoneAclType(OzoneAclType.ANONYMOUS, acl, ugi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to check acl access for OzoneAclType.
|
||||||
|
* */
|
||||||
|
private boolean checkAccessForOzoneAclType(OzoneAclType identityType,
|
||||||
|
ACLType acl, UserGroupInformation ugi) {
|
||||||
|
|
||||||
|
switch (identityType) {
|
||||||
|
case USER:
|
||||||
|
return OzoneUtils.checkIfAclBitIsSet(acl, getAcl(identityType,
|
||||||
|
ugi.getUserName()));
|
||||||
|
case GROUP:
|
||||||
|
// Check access for user groups.
|
||||||
|
for (String userGroup : ugi.getGroupNames()) {
|
||||||
|
if (OzoneUtils.checkIfAclBitIsSet(acl, getAcl(identityType,
|
||||||
|
userGroup))) {
|
||||||
|
// Return true if any user group has required permission.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// For type WORLD and ANONYMOUS we set acl type as name.
|
||||||
|
if(OzoneUtils.checkIfAclBitIsSet(acl, getAcl(identityType,
|
||||||
|
identityType.name()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,13 +237,12 @@ public class OmOzoneAclMap {
|
||||||
aclMaps.get(type.ordinal()).entrySet()) {
|
aclMaps.get(type.ordinal()).entrySet()) {
|
||||||
OzoneAclInfo.Builder builder = OzoneAclInfo.newBuilder()
|
OzoneAclInfo.Builder builder = OzoneAclInfo.newBuilder()
|
||||||
.setName(entry.getKey())
|
.setName(entry.getKey())
|
||||||
.setType(type);
|
.setType(type)
|
||||||
entry.getValue().stream().forEach(a ->
|
.setRights(ByteString.copyFrom(entry.getValue().toByteArray()));
|
||||||
builder.addRights(OzoneAclRights.values()[a]));
|
|
||||||
aclList.add(builder.build());
|
aclList.add(builder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return aclList;
|
return aclList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1073,6 +1073,8 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
|
||||||
.setVolumeName(omKeyArgs.getVolumeName())
|
.setVolumeName(omKeyArgs.getVolumeName())
|
||||||
.setBucketName(omKeyArgs.getBucketName())
|
.setBucketName(omKeyArgs.getBucketName())
|
||||||
.setKeyName(omKeyArgs.getKeyName())
|
.setKeyName(omKeyArgs.getKeyName())
|
||||||
|
.addAllAcls(omKeyArgs.getAcls().stream().map(a ->
|
||||||
|
OzoneAcl.toProtobuf(a)).collect(Collectors.toList()))
|
||||||
.setMultipartUploadID(omKeyArgs.getMultipartUploadID());
|
.setMultipartUploadID(omKeyArgs.getMultipartUploadID());
|
||||||
|
|
||||||
multipartUploadCompleteRequest.setKeyArgs(keyArgs.build());
|
multipartUploadCompleteRequest.setKeyArgs(keyArgs.build());
|
||||||
|
|
|
@ -38,17 +38,12 @@ import org.apache.hadoop.ozone.protocol.proto
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo;
|
.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.protocol.proto
|
import org.apache.hadoop.ozone.protocol.proto
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclType;
|
||||||
import org.apache.hadoop.ozone.protocol.proto
|
|
||||||
.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclRights;
|
|
||||||
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
|
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
||||||
import org.apache.hadoop.security.proto.SecurityProtos.TokenProto;
|
import org.apache.hadoop.security.proto.SecurityProtos.TokenProto;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for converting protobuf classes.
|
* Utilities for converting protobuf classes.
|
||||||
|
@ -84,14 +79,10 @@ public final class OMPBHelper {
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("ACL type is not recognized");
|
throw new IllegalArgumentException("ACL type is not recognized");
|
||||||
}
|
}
|
||||||
List<OzoneAclRights> ozAclRights =
|
|
||||||
new ArrayList<>(acl.getAclBitSet().cardinality());
|
|
||||||
acl.getAclBitSet().stream().forEach(a -> ozAclRights.add(
|
|
||||||
OzoneAclRights.valueOf(ACLType.values()[a].name())));
|
|
||||||
|
|
||||||
return OzoneAclInfo.newBuilder().setType(aclType)
|
return OzoneAclInfo.newBuilder().setType(aclType)
|
||||||
.setName(acl.getName())
|
.setName(acl.getName())
|
||||||
.addAllRights(ozAclRights)
|
.setRights(ByteString.copyFrom(acl.getAclBitSet().toByteArray()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +112,7 @@ public final class OMPBHelper {
|
||||||
throw new IllegalArgumentException("ACL type is not recognized");
|
throw new IllegalArgumentException("ACL type is not recognized");
|
||||||
}
|
}
|
||||||
|
|
||||||
BitSet aclRights = new BitSet(ACLType.getNoOfAcls());
|
BitSet aclRights = BitSet.valueOf(aclInfo.getRights().toByteArray());
|
||||||
aclInfo.getRightsList().stream().forEach(a ->
|
|
||||||
aclRights.set(ACLType.valueOf(a.name()).ordinal()));
|
|
||||||
return new OzoneAcl(aclType, aclInfo.getName(), aclRights);
|
return new OzoneAcl(aclType, aclInfo.getName(), aclRights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,11 +56,20 @@ public interface IAccessAuthorizer {
|
||||||
ALL,
|
ALL,
|
||||||
NONE;
|
NONE;
|
||||||
private static int length = ACLType.values().length;
|
private static int length = ACLType.values().length;
|
||||||
|
private static ACLType[] vals = ACLType.values();
|
||||||
|
|
||||||
public static int getNoOfAcls() {
|
public static int getNoOfAcls() {
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ACLType getAclTypeFromOrdinal(int ordinal) {
|
||||||
|
if (ordinal > length - 1 && ordinal > -1) {
|
||||||
|
throw new IllegalArgumentException("Ordinal greater than array lentgh" +
|
||||||
|
". ordinal:" + ordinal);
|
||||||
|
}
|
||||||
|
return vals[ordinal];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ACL rights based on passed in String.
|
* Returns the ACL rights based on passed in String.
|
||||||
*
|
*
|
||||||
|
@ -145,9 +154,11 @@ public interface IAccessAuthorizer {
|
||||||
enum ACLIdentityType {
|
enum ACLIdentityType {
|
||||||
USER(OzoneConsts.OZONE_ACL_USER_TYPE),
|
USER(OzoneConsts.OZONE_ACL_USER_TYPE),
|
||||||
GROUP(OzoneConsts.OZONE_ACL_GROUP_TYPE),
|
GROUP(OzoneConsts.OZONE_ACL_GROUP_TYPE),
|
||||||
CLIENT_IP(OzoneConsts.OZONE_ACL_IP_TYPE),
|
|
||||||
WORLD(OzoneConsts.OZONE_ACL_WORLD_TYPE),
|
WORLD(OzoneConsts.OZONE_ACL_WORLD_TYPE),
|
||||||
ANONYMOUS(OzoneConsts.OZONE_ACL_ANONYMOUS_TYPE);
|
ANONYMOUS(OzoneConsts.OZONE_ACL_ANONYMOUS_TYPE),
|
||||||
|
CLIENT_IP(OzoneConsts.OZONE_ACL_IP_TYPE);
|
||||||
|
|
||||||
|
// TODO: Add support for acl checks based on CLIENT_IP.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.nio.charset.Charset;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.BitSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
@ -37,11 +38,16 @@ import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
import org.apache.hadoop.ozone.OzoneConsts;
|
import org.apache.hadoop.ozone.OzoneConsts;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
import org.apache.ratis.util.TimeDuration;
|
import org.apache.ratis.util.TimeDuration;
|
||||||
|
|
||||||
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.GROUP;
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.GROUP;
|
||||||
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.NONE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set of Utility functions used in ozone.
|
* Set of Utility functions used in ozone.
|
||||||
|
@ -260,9 +266,103 @@ public final class OzoneUtils {
|
||||||
listOfAcls.add(new OzoneAcl(USER, userName, userRights));
|
listOfAcls.add(new OzoneAcl(USER, userName, userRights));
|
||||||
if(userGroups != null) {
|
if(userGroups != null) {
|
||||||
// Group ACLs of the User.
|
// Group ACLs of the User.
|
||||||
userGroups.stream().forEach((group) -> listOfAcls.add(
|
userGroups.forEach((group) -> listOfAcls.add(
|
||||||
new OzoneAcl(GROUP, group, groupRights)));
|
new OzoneAcl(GROUP, group, groupRights)));
|
||||||
}
|
}
|
||||||
return listOfAcls;
|
return listOfAcls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if acl right requested for given RequestContext exist
|
||||||
|
* in provided acl list.
|
||||||
|
* Acl validation rules:
|
||||||
|
* 1. If user/group has ALL bit set than all user should have all rights.
|
||||||
|
* 2. If user/group has NONE bit set than user/group will not have any right.
|
||||||
|
* 3. For all other individual rights individual bits should be set.
|
||||||
|
*
|
||||||
|
* @param acls
|
||||||
|
* @param context
|
||||||
|
* @return return true if acl list contains right requsted in context.
|
||||||
|
* */
|
||||||
|
public static boolean checkAclRight(List<OzoneAclInfo> acls,
|
||||||
|
RequestContext context) throws OMException {
|
||||||
|
String[] userGroups = context.getClientUgi().getGroupNames();
|
||||||
|
String userName = context.getClientUgi().getUserName();
|
||||||
|
ACLType aclToCheck = context.getAclRights();
|
||||||
|
for (OzoneAclInfo a : acls) {
|
||||||
|
if(checkAccessInAcl(a, userGroups, userName, aclToCheck)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean checkAccessInAcl(OzoneAclInfo a, String[] groups,
|
||||||
|
String username, ACLType aclToCheck) {
|
||||||
|
BitSet rights = BitSet.valueOf(a.getRights().toByteArray());
|
||||||
|
switch (a.getType()) {
|
||||||
|
case USER:
|
||||||
|
if (a.getName().equals(username)) {
|
||||||
|
return checkIfAclBitIsSet(aclToCheck, rights);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GROUP:
|
||||||
|
for (String grp : groups) {
|
||||||
|
// TODO: Convert ozone acls to proto map format for efficient
|
||||||
|
// acl checks.
|
||||||
|
if (a.getName().equals(grp)) {
|
||||||
|
return checkIfAclBitIsSet(aclToCheck, rights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return checkIfAclBitIsSet(aclToCheck, rights);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if acl right requested for given RequestContext exist
|
||||||
|
* in provided acl list.
|
||||||
|
* Acl validation rules:
|
||||||
|
* 1. If user/group has ALL bit set than all user should have all rights.
|
||||||
|
* 2. If user/group has NONE bit set than user/group will not have any right.
|
||||||
|
* 3. For all other individual rights individual bits should be set.
|
||||||
|
*
|
||||||
|
* @param acls
|
||||||
|
* @param context
|
||||||
|
* @return return true if acl list contains right requsted in context.
|
||||||
|
* */
|
||||||
|
public static boolean checkAclRights(List<OzoneAcl> acls,
|
||||||
|
RequestContext context) throws OMException {
|
||||||
|
String[] userGroups = context.getClientUgi().getGroupNames();
|
||||||
|
String userName = context.getClientUgi().getUserName();
|
||||||
|
ACLType aclToCheck = context.getAclRights();
|
||||||
|
// TODO: All ozone types should use one data type for acls. i.e Store
|
||||||
|
// and maintain acls in proto format only.
|
||||||
|
for (OzoneAcl a : acls) {
|
||||||
|
if (checkAccessInAcl(OzoneAcl.toProtobuf(a), userGroups,
|
||||||
|
userName, aclToCheck)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to check if bit for given acl is set.
|
||||||
|
* @param acl
|
||||||
|
* @param bitset
|
||||||
|
* @return True of acl bit is set else false.
|
||||||
|
* */
|
||||||
|
public static boolean checkIfAclBitIsSet(ACLType acl, BitSet bitset) {
|
||||||
|
if (bitset == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((bitset.get(acl.ordinal())
|
||||||
|
|| bitset.get(ALL.ordinal()))
|
||||||
|
&& !bitset.get(NONE.ordinal()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -507,20 +507,9 @@ message OzoneAclInfo {
|
||||||
CLIENT_IP = 5;
|
CLIENT_IP = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OzoneAclRights {
|
|
||||||
READ = 1;
|
|
||||||
WRITE = 2;
|
|
||||||
CREATE = 3;
|
|
||||||
LIST = 4;
|
|
||||||
DELETE = 5;
|
|
||||||
READ_ACL = 6;
|
|
||||||
WRITE_ACL = 7;
|
|
||||||
ALL = 8;
|
|
||||||
NONE = 9;
|
|
||||||
}
|
|
||||||
required OzoneAclType type = 1;
|
required OzoneAclType type = 1;
|
||||||
required string name = 2;
|
required string name = 2;
|
||||||
repeated OzoneAclRights rights = 3;
|
required bytes rights = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetAclRequest {
|
message GetAclRequest {
|
||||||
|
|
|
@ -105,6 +105,10 @@ public class TestOzoneAcls {
|
||||||
|
|
||||||
testMatrix.put(" world:bilbo:w", Boolean.FALSE);
|
testMatrix.put(" world:bilbo:w", Boolean.FALSE);
|
||||||
testMatrix.put(" world:bilbo:rw", Boolean.FALSE);
|
testMatrix.put(" world:bilbo:rw", Boolean.FALSE);
|
||||||
|
testMatrix.put(" anonymous:bilbo:w", Boolean.FALSE);
|
||||||
|
testMatrix.put(" anonymous:ANONYMOUS:w", Boolean.TRUE);
|
||||||
|
testMatrix.put(" anonymous::rw", Boolean.TRUE);
|
||||||
|
testMatrix.put(" world:WORLD:rw", Boolean.TRUE);
|
||||||
|
|
||||||
Set<String> keys = testMatrix.keySet();
|
Set<String> keys = testMatrix.keySet();
|
||||||
for (String key : keys) {
|
for (String key : keys) {
|
||||||
|
@ -157,7 +161,7 @@ public class TestOzoneAcls {
|
||||||
assertEquals(ACLIdentityType.GROUP, acl.getType());
|
assertEquals(ACLIdentityType.GROUP, acl.getType());
|
||||||
|
|
||||||
acl = OzoneAcl.parseAcl("world::a");
|
acl = OzoneAcl.parseAcl("world::a");
|
||||||
assertEquals(acl.getName(), "");
|
assertEquals(acl.getName(), "WORLD");
|
||||||
assertTrue(acl.getAclBitSet().get(ALL.ordinal()));
|
assertTrue(acl.getAclBitSet().get(ALL.ordinal()));
|
||||||
assertFalse(acl.getAclBitSet().get(WRITE.ordinal()));
|
assertFalse(acl.getAclBitSet().get(WRITE.ordinal()));
|
||||||
assertEquals(ACLIdentityType.WORLD, acl.getType());
|
assertEquals(ACLIdentityType.WORLD, acl.getType());
|
||||||
|
@ -188,7 +192,7 @@ public class TestOzoneAcls {
|
||||||
assertEquals(ACLIdentityType.GROUP, acl.getType());
|
assertEquals(ACLIdentityType.GROUP, acl.getType());
|
||||||
|
|
||||||
acl = OzoneAcl.parseAcl("world::rwdlncxy");
|
acl = OzoneAcl.parseAcl("world::rwdlncxy");
|
||||||
assertEquals(acl.getName(), "");
|
assertEquals(acl.getName(), "WORLD");
|
||||||
assertTrue(acl.getAclBitSet().get(READ.ordinal()));
|
assertTrue(acl.getAclBitSet().get(READ.ordinal()));
|
||||||
assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
|
assertTrue(acl.getAclBitSet().get(WRITE.ordinal()));
|
||||||
assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
|
assertTrue(acl.getAclBitSet().get(DELETE.ordinal()));
|
||||||
|
|
|
@ -31,6 +31,7 @@ OZONE-SITE.XML_ozone.om.kerberos.principal=om/om@EXAMPLE.COM
|
||||||
OZONE-SITE.XML_ozone.om.kerberos.keytab.file=/etc/security/keytabs/om.keytab
|
OZONE-SITE.XML_ozone.om.kerberos.keytab.file=/etc/security/keytabs/om.keytab
|
||||||
OZONE-SITE.XML_ozone.s3g.keytab.file=/etc/security/keytabs/HTTP.keytab
|
OZONE-SITE.XML_ozone.s3g.keytab.file=/etc/security/keytabs/HTTP.keytab
|
||||||
OZONE-SITE.XML_ozone.s3g.authentication.kerberos.principal=HTTP/s3g@EXAMPLE.COM
|
OZONE-SITE.XML_ozone.s3g.authentication.kerberos.principal=HTTP/s3g@EXAMPLE.COM
|
||||||
|
OZONE_SITE.XML_ozone.administrators=*
|
||||||
|
|
||||||
OZONE-SITE.XML_ozone.security.enabled=true
|
OZONE-SITE.XML_ozone.security.enabled=true
|
||||||
OZONE-SITE.XML_hdds.scm.http.kerberos.principal=HTTP/scm@EXAMPLE.COM
|
OZONE-SITE.XML_hdds.scm.http.kerberos.principal=HTTP/scm@EXAMPLE.COM
|
||||||
|
|
|
@ -35,6 +35,9 @@ OZONE-SITE.XML_ozone.s3g.keytab.file=/etc/security/keytabs/HTTP.keytab
|
||||||
OZONE-SITE.XML_ozone.s3g.authentication.kerberos.principal=HTTP/s3g@EXAMPLE.COM
|
OZONE-SITE.XML_ozone.s3g.authentication.kerberos.principal=HTTP/s3g@EXAMPLE.COM
|
||||||
|
|
||||||
OZONE-SITE.XML_ozone.security.enabled=true
|
OZONE-SITE.XML_ozone.security.enabled=true
|
||||||
|
OZONE-SITE.XML_ozone.acl.enabled=true
|
||||||
|
OZONE-SITE.XML_ozone.acl.authorizer.class=org.apache.hadoop.ozone.security.acl.OzoneNativeAuthorizer
|
||||||
|
OZONE-SITE.XML_ozone.administrators=*
|
||||||
OZONE-SITE.XML_hdds.scm.http.kerberos.principal=HTTP/scm@EXAMPLE.COM
|
OZONE-SITE.XML_hdds.scm.http.kerberos.principal=HTTP/scm@EXAMPLE.COM
|
||||||
OZONE-SITE.XML_hdds.scm.http.kerberos.keytab.file=/etc/security/keytabs/HTTP.keytab
|
OZONE-SITE.XML_hdds.scm.http.kerberos.keytab.file=/etc/security/keytabs/HTTP.keytab
|
||||||
OZONE-SITE.XML_ozone.om.http.kerberos.principal=HTTP/om@EXAMPLE.COM
|
OZONE-SITE.XML_ozone.om.http.kerberos.principal=HTTP/om@EXAMPLE.COM
|
||||||
|
@ -112,7 +115,7 @@ LOG4J2.PROPERTIES_rootLogger.appenderRef.stdout.ref=STDOUT
|
||||||
OZONE_DATANODE_SECURE_USER=root
|
OZONE_DATANODE_SECURE_USER=root
|
||||||
SECURITY_ENABLED=true
|
SECURITY_ENABLED=true
|
||||||
KEYTAB_DIR=/etc/security/keytabs
|
KEYTAB_DIR=/etc/security/keytabs
|
||||||
KERBEROS_KEYTABS=dn om scm HTTP testuser s3g
|
KERBEROS_KEYTABS=dn om scm HTTP testuser testuser2 s3g
|
||||||
KERBEROS_KEYSTORES=hadoop
|
KERBEROS_KEYSTORES=hadoop
|
||||||
KERBEROS_SERVER=kdc
|
KERBEROS_SERVER=kdc
|
||||||
JAVA_HOME=/usr/lib/jvm/jre
|
JAVA_HOME=/usr/lib/jvm/jre
|
||||||
|
|
|
@ -15,4 +15,4 @@
|
||||||
*** Settings ***
|
*** Settings ***
|
||||||
Documentation Smoketest ozone secure cluster
|
Documentation Smoketest ozone secure cluster
|
||||||
Resource commonlib.robot
|
Resource commonlib.robot
|
||||||
Suite Setup Run Keyword if '${SECURITY_ENABLED}' == 'true' Kinit test user
|
Suite Setup Run Keyword if '${SECURITY_ENABLED}' == 'true' Kinit test user testuser testuser.keytab
|
|
@ -44,16 +44,17 @@ RpcClient without scheme
|
||||||
*** Keywords ***
|
*** Keywords ***
|
||||||
Test ozone shell
|
Test ozone shell
|
||||||
[arguments] ${protocol} ${server} ${volume}
|
[arguments] ${protocol} ${server} ${volume}
|
||||||
${result} = Execute ozone sh volume create ${protocol}${server}/${volume} --user bilbo --quota 100TB --root
|
${result} = Execute ozone sh volume create ${protocol}${server}/${volume} --quota 100TB
|
||||||
Should not contain ${result} Failed
|
Should not contain ${result} Failed
|
||||||
Should contain ${result} Creating Volume: ${volume}
|
Should contain ${result} Creating Volume: ${volume}
|
||||||
${result} = Execute ozone sh volume list ${protocol}${server}/ --user bilbo | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '.[] | select(.volumeName=="${volume}")'
|
${result} = Execute ozone sh volume list ${protocol}${server}/ | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '.[] | select(.volumeName=="${volume}")'
|
||||||
Should contain ${result} createdOn
|
Should contain ${result} createdOn
|
||||||
${result} = Execute ozone sh volume list --user bilbo | grep -Ev 'Removed|DEBUG|ERROR|INFO|TRACE|WARN' | jq -r '.[] | select(.volumeName=="${volume}")'
|
${result} = Execute ozone sh volume list | grep -Ev 'Removed|DEBUG|ERROR|INFO|TRACE|WARN' | jq -r '.[] | select(.volumeName=="${volume}")'
|
||||||
Should contain ${result} createdOn
|
Should contain ${result} createdOn
|
||||||
Execute ozone sh volume update ${protocol}${server}/${volume} --user bill --quota 10TB
|
# TODO: Disable updating the owner, acls should be used to give access to other user.
|
||||||
${result} = Execute ozone sh volume info ${protocol}${server}/${volume} | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '. | select(.volumeName=="${volume}") | .owner | .name'
|
Execute ozone sh volume update ${protocol}${server}/${volume} --quota 10TB
|
||||||
Should Be Equal ${result} bill
|
# ${result} = Execute ozone sh volume info ${protocol}${server}/${volume} | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '. | select(.volumeName=="${volume}") | .owner | .name'
|
||||||
|
# Should Be Equal ${result} bill
|
||||||
${result} = Execute ozone sh volume info ${protocol}${server}/${volume} | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '. | select(.volumeName=="${volume}") | .quota | .size'
|
${result} = Execute ozone sh volume info ${protocol}${server}/${volume} | grep -Ev 'Removed|WARN|DEBUG|ERROR|INFO|TRACE' | jq -r '. | select(.volumeName=="${volume}") | .quota | .size'
|
||||||
Should Be Equal ${result} 10
|
Should Be Equal ${result} 10
|
||||||
Execute ozone sh bucket create ${protocol}${server}/${volume}/bb1
|
Execute ozone sh bucket create ${protocol}${server}/${volume}/bb1
|
||||||
|
@ -67,7 +68,7 @@ Test ozone shell
|
||||||
Should Be Equal ${result} ${volume}
|
Should Be Equal ${result} ${volume}
|
||||||
Run Keyword Test key handling ${protocol} ${server} ${volume}
|
Run Keyword Test key handling ${protocol} ${server} ${volume}
|
||||||
Execute ozone sh bucket delete ${protocol}${server}/${volume}/bb1
|
Execute ozone sh bucket delete ${protocol}${server}/${volume}/bb1
|
||||||
Execute ozone sh volume delete ${protocol}${server}/${volume} --user bilbo
|
Execute ozone sh volume delete ${protocol}${server}/${volume}
|
||||||
|
|
||||||
Test Volume Acls
|
Test Volume Acls
|
||||||
[arguments] ${protocol} ${server} ${volume}
|
[arguments] ${protocol} ${server} ${volume}
|
||||||
|
@ -80,7 +81,7 @@ Test Volume Acls
|
||||||
${result} = Execute ozone sh volume removeacl ${protocol}${server}/${volume} -a user:superuser1:xy
|
${result} = Execute ozone sh volume removeacl ${protocol}${server}/${volume} -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh volume getacl ${protocol}${server}/${volume}
|
${result} = Execute ozone sh volume getacl ${protocol}${server}/${volume}
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh volume setacl ${protocol}${server}/${volume} -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh volume setacl ${protocol}${server}/${volume} -al user:superuser1:rwxy,group:superuser1:a,user:testuser/scm@EXAMPLE.COM:rwxyc
|
||||||
${result} = Execute ozone sh volume getacl ${protocol}${server}/${volume}
|
${result} = Execute ozone sh volume getacl ${protocol}${server}/${volume}
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
||||||
|
@ -96,7 +97,7 @@ Test Bucket Acls
|
||||||
${result} = Execute ozone sh bucket removeacl ${protocol}${server}/${volume}/bb1 -a user:superuser1:xy
|
${result} = Execute ozone sh bucket removeacl ${protocol}${server}/${volume}/bb1 -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh bucket getacl ${protocol}${server}/${volume}/bb1
|
${result} = Execute ozone sh bucket getacl ${protocol}${server}/${volume}/bb1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh bucket setacl ${protocol}${server}/${volume}/bb1 -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh bucket setacl ${protocol}${server}/${volume}/bb1 -al user:superuser1:rwxy,group:superuser1:a,user:testuser/scm@EXAMPLE.COM:rwxyc
|
||||||
${result} = Execute ozone sh bucket getacl ${protocol}${server}/${volume}/bb1
|
${result} = Execute ozone sh bucket getacl ${protocol}${server}/${volume}/bb1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
||||||
|
@ -128,7 +129,7 @@ Test key Acls
|
||||||
${result} = Execute ozone sh key removeacl ${protocol}${server}/${volume}/bb1/key2 -a user:superuser1:xy
|
${result} = Execute ozone sh key removeacl ${protocol}${server}/${volume}/bb1/key2 -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh key getacl ${protocol}${server}/${volume}/bb1/key2
|
${result} = Execute ozone sh key getacl ${protocol}${server}/${volume}/bb1/key2
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh key setacl ${protocol}${server}/${volume}/bb1/key2 -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh key setacl ${protocol}${server}/${volume}/bb1/key2 -al user:superuser1:rwxy,group:superuser1:a,user:testuser/scm@EXAMPLE.COM:rwxyc
|
||||||
${result} = Execute ozone sh key getacl ${protocol}${server}/${volume}/bb1/key2
|
${result} = Execute ozone sh key getacl ${protocol}${server}/${volume}/bb1/key2
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
|
@ -55,6 +55,7 @@ Install aws cli
|
||||||
Run Keyword if '${rc}' == '0' Install aws cli s3 centos
|
Run Keyword if '${rc}' == '0' Install aws cli s3 centos
|
||||||
|
|
||||||
Kinit test user
|
Kinit test user
|
||||||
|
[arguments] ${user} ${keytab}
|
||||||
${hostname} = Execute hostname
|
${hostname} = Execute hostname
|
||||||
Set Suite Variable ${TEST_USER} testuser/${hostname}@EXAMPLE.COM
|
Set Suite Variable ${TEST_USER} ${user}/${hostname}@EXAMPLE.COM
|
||||||
Wait Until Keyword Succeeds 2min 10sec Execute kinit -k ${TEST_USER} -t /etc/security/keytabs/testuser.keytab
|
Wait Until Keyword Succeeds 2min 10sec Execute kinit -k ${user}/${hostname}@EXAMPLE.COM -t /etc/security/keytabs/${keytab}
|
|
@ -27,7 +27,7 @@ ${bucket} bucket1
|
||||||
|
|
||||||
*** Keywords ***
|
*** Keywords ***
|
||||||
Create volume
|
Create volume
|
||||||
${result} = Execute ozone sh volume create /${volume} --user hadoop --quota 100TB --root
|
${result} = Execute ozone sh volume create /${volume} --user hadoop --quota 100TB
|
||||||
Should not contain ${result} Failed
|
Should not contain ${result} Failed
|
||||||
Should contain ${result} Creating Volume: ${volume}
|
Should contain ${result} Creating Volume: ${volume}
|
||||||
Create bucket
|
Create bucket
|
||||||
|
|
|
@ -27,7 +27,7 @@ ${bucket} bucket1
|
||||||
|
|
||||||
*** Keywords ***
|
*** Keywords ***
|
||||||
Create volume
|
Create volume
|
||||||
${result} = Execute ozone sh volume create /${volume} --user hadoop --quota 100TB --root
|
${result} = Execute ozone sh volume create /${volume} --user hadoop --quota 100TB
|
||||||
Should not contain ${result} Failed
|
Should not contain ${result} Failed
|
||||||
Should contain ${result} Creating Volume: ${volume}
|
Should contain ${result} Creating Volume: ${volume}
|
||||||
Create bucket
|
Create bucket
|
||||||
|
|
|
@ -22,4 +22,4 @@ Test Timeout 2 minute
|
||||||
|
|
||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
Kinit
|
Kinit
|
||||||
Kinit test user
|
Kinit test user testuser testuser.keytab
|
||||||
|
|
|
@ -23,11 +23,11 @@ Resource ../commonlib.robot
|
||||||
|
|
||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
Create volume and bucket
|
Create volume and bucket
|
||||||
Execute ozone sh volume create http://om/fstest --user bilbo --quota 100TB --root
|
Execute ozone sh volume create o3://om/fstest --quota 100TB
|
||||||
Execute ozone sh volume create http://om/fstest2 --user bilbo --quota 100TB --root
|
Execute ozone sh volume create o3://om/fstest2 --quota 100TB
|
||||||
Execute ozone sh bucket create http://om/fstest/bucket1
|
Execute ozone sh bucket create o3://om/fstest/bucket1
|
||||||
Execute ozone sh bucket create http://om/fstest/bucket2
|
Execute ozone sh bucket create o3://om/fstest/bucket2
|
||||||
Execute ozone sh bucket create http://om/fstest2/bucket3
|
Execute ozone sh bucket create o3://om/fstest2/bucket3
|
||||||
|
|
||||||
Check volume from ozonefs
|
Check volume from ozonefs
|
||||||
${result} = Execute ozone fs -ls o3fs://bucket1.fstest/
|
${result} = Execute ozone fs -ls o3fs://bucket1.fstest/
|
||||||
|
@ -109,4 +109,4 @@ Run ozoneFS tests
|
||||||
Execute ls -l GET.txt
|
Execute ls -l GET.txt
|
||||||
${rc} ${result} = Run And Return Rc And Output ozone fs -ls o3fs://abcde.pqrs/
|
${rc} ${result} = Run And Return Rc And Output ozone fs -ls o3fs://abcde.pqrs/
|
||||||
Should Be Equal As Integers ${rc} 1
|
Should Be Equal As Integers ${rc} 1
|
||||||
Should contain ${result} not found
|
Should Match Regexp ${result} (Check access operation failed)|(Volume pqrs is not found)
|
||||||
|
|
|
@ -41,7 +41,7 @@ File upload and directory list
|
||||||
Should not contain ${result} testfile
|
Should not contain ${result} testfile
|
||||||
Should not contain ${result} dir1
|
Should not contain ${result} dir1
|
||||||
Should contain ${result} dir2
|
Should contain ${result} dir2
|
||||||
${result} = Execute AWSS3Cli ls s3://${BUCKET}/dir1/dir2/
|
${result} = Execute AWSS3Cli ls s3://${BUCKET}/dir1/dir2/file
|
||||||
Should not contain ${result} testfile
|
Should not contain ${result} testfile
|
||||||
Should not contain ${result} dir1
|
Should not contain ${result} dir1
|
||||||
Should contain ${result} file
|
Should contain ${result} file
|
||||||
|
|
|
@ -33,15 +33,15 @@ Setup volume names
|
||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
Create volume bucket with wrong credentials
|
Create volume bucket with wrong credentials
|
||||||
Execute kdestroy
|
Execute kdestroy
|
||||||
${rc} ${output} = Run And Return Rc And Output ozone sh volume create o3://om/fstest --user bilbo --quota 100TB --root
|
${rc} ${output} = Run And Return Rc And Output ozone sh volume create o3://om/fstest
|
||||||
Should contain ${output} Client cannot authenticate via
|
Should contain ${output} Client cannot authenticate via
|
||||||
|
|
||||||
Create volume bucket with credentials
|
Create volume bucket with credentials
|
||||||
# Authenticate testuser
|
# Authenticate testuser
|
||||||
Run Keyword Kinit test user
|
Run Keyword Kinit test user testuser testuser.keytab
|
||||||
Run Keyword Setup volume names
|
Run Keyword Setup volume names
|
||||||
Execute ozone sh volume create o3://om/${volume1} --user bilbo --quota 100TB --root
|
Execute ozone sh volume create o3://om/${volume1}
|
||||||
Execute ozone sh volume create o3://om/${volume2} --user bilbo --quota 100TB --root
|
Execute ozone sh volume create o3://om/${volume2}
|
||||||
Execute ozone sh bucket create o3://om/${volume1}/bucket1
|
Execute ozone sh bucket create o3://om/${volume1}/bucket1
|
||||||
Execute ozone sh bucket create o3://om/${volume1}/bucket2
|
Execute ozone sh bucket create o3://om/${volume1}/bucket2
|
||||||
Execute ozone sh bucket create o3://om/${volume2}/bucket3
|
Execute ozone sh bucket create o3://om/${volume2}/bucket3
|
||||||
|
@ -60,7 +60,7 @@ Test Volume Acls
|
||||||
${result} = Execute ozone sh volume removeacl ${volume3} -a user:superuser1:xy
|
${result} = Execute ozone sh volume removeacl ${volume3} -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh volume getacl ${volume3}
|
${result} = Execute ozone sh volume getacl ${volume3}
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh volume setacl ${volume3} -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh volume setacl ${volume3} -al user:superuser1:rwxy,user:testuser/scm@EXAMPLE.COM:rwxyc,group:superuser1:a
|
||||||
${result} = Execute ozone sh volume getacl ${volume3}
|
${result} = Execute ozone sh volume getacl ${volume3}
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
||||||
|
@ -76,7 +76,7 @@ Test Bucket Acls
|
||||||
${result} = Execute ozone sh bucket removeacl ${volume3}/bk1 -a user:superuser1:xy
|
${result} = Execute ozone sh bucket removeacl ${volume3}/bk1 -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh bucket getacl ${volume3}/bk1
|
${result} = Execute ozone sh bucket getacl ${volume3}/bk1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh bucket setacl ${volume3}/bk1 -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh bucket setacl ${volume3}/bk1 -al user:superuser1:rwxy,group:superuser1:a,user:testuser/scm@EXAMPLE.COM:rwxyc
|
||||||
${result} = Execute ozone sh bucket getacl ${volume3}/bk1
|
${result} = Execute ozone sh bucket getacl ${volume3}/bk1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
||||||
|
@ -91,7 +91,41 @@ Test key Acls
|
||||||
${result} = Execute ozone sh key removeacl ${volume3}/bk1/key1 -a user:superuser1:xy
|
${result} = Execute ozone sh key removeacl ${volume3}/bk1/key1 -a user:superuser1:xy
|
||||||
${result} = Execute ozone sh key getacl ${volume3}/bk1/key1
|
${result} = Execute ozone sh key getacl ${volume3}/bk1/key1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"READ\", \"WRITE\"
|
||||||
${result} = Execute ozone sh key setacl ${volume3}/bk1/key1 -al user:superuser1:rwxy,group:superuser1:a
|
${result} = Execute ozone sh key setacl ${volume3}/bk1/key1 -al user:superuser1:rwxy,group:superuser1:a,user:testuser/scm@EXAMPLE.COM:rwxyc
|
||||||
${result} = Execute ozone sh key getacl ${volume3}/bk1/key1
|
${result} = Execute ozone sh key getacl ${volume3}/bk1/key1
|
||||||
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
Should Match Regexp ${result} \"type\" : \"USER\",\n.*\"name\" : \"superuser1*\",\n.*\"aclList\" : . \"READ\", \"WRITE\", \"READ_ACL\", \"WRITE_ACL\"
|
||||||
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
Should Match Regexp ${result} \"type\" : \"GROUP\",\n.*\"name\" : \"superuser1\",\n.*\"aclList\" : . \"ALL\"
|
||||||
|
|
||||||
|
Test native authorizer
|
||||||
|
Execute ozone sh volume removeacl ${volume3} -a group:root:a
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser2 testuser2.keytab
|
||||||
|
${result} = Execute And Ignore Error ozone sh bucket list /${volume3}/
|
||||||
|
Should contain ${result} PERMISSION_DENIED
|
||||||
|
${result} = Execute And Ignore Error ozone sh key list /${volume3}/bk1
|
||||||
|
Should contain ${result} PERMISSION_DENIED
|
||||||
|
${result} = Execute And Ignore Error ozone sh volume addacl ${volume3} -a user:testuser2/scm@EXAMPLE.COM:xy
|
||||||
|
Should contain ${result} PERMISSION_DENIED User testuser2/scm@EXAMPLE.COM doesn't have WRITE_ACL permission to access volume
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser testuser.keytab
|
||||||
|
Execute ozone sh volume addacl ${volume3} -a user:testuser2/scm@EXAMPLE.COM:xyrw
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser2 testuser2.keytab
|
||||||
|
${result} = Execute And Ignore Error ozone sh bucket list /${volume3}/
|
||||||
|
Should contain ${result} PERMISSION_DENIED org.apache.hadoop.ozone.om.exceptions.OMException: User testuser2/scm@EXAMPLE.COM doesn't have LIST permission to access volume
|
||||||
|
Execute ozone sh volume addacl ${volume3} -a user:testuser2/scm@EXAMPLE.COM:l
|
||||||
|
Execute ozone sh bucket list /${volume3}/
|
||||||
|
Execute ozone sh volume getacl /${volume3}/
|
||||||
|
|
||||||
|
${result} = Execute And Ignore Error ozone sh key list /${volume3}/bk1
|
||||||
|
Should contain ${result} PERMISSION_DENIED
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser testuser.keytab
|
||||||
|
Execute ozone sh bucket addacl ${volume3}/bk1 -a user:testuser2/scm@EXAMPLE.COM:a
|
||||||
|
Execute ozone sh bucket getacl /${volume3}/bk1
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser2 testuser2.keytab
|
||||||
|
Execute ozone sh bucket getacl /${volume3}/bk1
|
||||||
|
Execute ozone sh key list /${volume3}/bk1
|
||||||
|
Execute kdestroy
|
||||||
|
Run Keyword Kinit test user testuser testuser.keytab
|
|
@ -24,6 +24,8 @@ import org.apache.hadoop.hdds.scm.ScmConfigKeys;
|
||||||
import org.apache.hadoop.ozone.recon.ReconServerConfigKeys;
|
import org.apache.hadoop.ozone.recon.ReconServerConfigKeys;
|
||||||
import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
|
import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_AUTHORIZER_CLASS_NATIVE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if configuration constants documented in ozone-defaults.xml.
|
* Tests if configuration constants documented in ozone-defaults.xml.
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +51,7 @@ public class TestOzoneConfigurationFields extends TestConfigurationFieldsBase {
|
||||||
configurationPropsToSkipCompare.add(HddsConfigKeys.HDDS_SECURITY_PROVIDER);
|
configurationPropsToSkipCompare.add(HddsConfigKeys.HDDS_SECURITY_PROVIDER);
|
||||||
configurationPropsToSkipCompare.add(HddsConfigKeys.HDDS_GRPC_TLS_TEST_CERT);
|
configurationPropsToSkipCompare.add(HddsConfigKeys.HDDS_GRPC_TLS_TEST_CERT);
|
||||||
configurationPropsToSkipCompare.add(OMConfigKeys.OZONE_OM_NODES_KEY);
|
configurationPropsToSkipCompare.add(OMConfigKeys.OZONE_OM_NODES_KEY);
|
||||||
|
configurationPropsToSkipCompare.add(OZONE_ACL_AUTHORIZER_CLASS_NATIVE);
|
||||||
configurationPropsToSkipCompare.add(OzoneConfigKeys.
|
configurationPropsToSkipCompare.add(OzoneConfigKeys.
|
||||||
OZONE_S3_TOKEN_MAX_LIFETIME_KEY);
|
OZONE_S3_TOKEN_MAX_LIFETIME_KEY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,7 +299,7 @@ public abstract class TestOzoneRpcClientAbstract {
|
||||||
public void testCreateS3Bucket()
|
public void testCreateS3Bucket()
|
||||||
throws IOException, OzoneException {
|
throws IOException, OzoneException {
|
||||||
long currentTime = Time.now();
|
long currentTime = Time.now();
|
||||||
String userName = "ozone";
|
String userName = UserGroupInformation.getCurrentUser().getUserName();
|
||||||
String bucketName = UUID.randomUUID().toString();
|
String bucketName = UUID.randomUUID().toString();
|
||||||
store.createS3Bucket(userName, bucketName);
|
store.createS3Bucket(userName, bucketName);
|
||||||
String volumeName = store.getOzoneVolumeName(bucketName);
|
String volumeName = store.getOzoneVolumeName(bucketName);
|
||||||
|
@ -2400,7 +2400,8 @@ public abstract class TestOzoneRpcClientAbstract {
|
||||||
assertTrue(acls.size() == expectedAcls.size());
|
assertTrue(acls.size() == expectedAcls.size());
|
||||||
for(OzoneAcl acl: acls) {
|
for(OzoneAcl acl: acls) {
|
||||||
if(acl.getName().equals(newAcl.getName())) {
|
if(acl.getName().equals(newAcl.getName())) {
|
||||||
assertFalse(acl.getAclList().contains(ACLType.READ_ACL));
|
assertFalse("READ_ACL should not exist in current acls:" +
|
||||||
|
acls, acl.getAclList().contains(ACLType.READ_ACL));
|
||||||
aclVerified = true;
|
aclVerified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,8 +124,8 @@ public class TestOmAcls {
|
||||||
logCapturer.clearOutput();
|
logCapturer.clearOutput();
|
||||||
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
||||||
() -> storageHandler.createVolume(createVolumeArgs));
|
() -> storageHandler.createVolume(createVolumeArgs));
|
||||||
assertTrue(logCapturer.getOutput().contains("doesn't have CREATE " +
|
assertTrue(logCapturer.getOutput().contains("Only admin users are " +
|
||||||
"permission to access volume"));
|
"authorized to create Ozone"));
|
||||||
|
|
||||||
BucketArgs bucketArgs = new BucketArgs("bucket1", createVolumeArgs);
|
BucketArgs bucketArgs = new BucketArgs("bucket1", createVolumeArgs);
|
||||||
bucketArgs.setAddAcls(new LinkedList<>());
|
bucketArgs.setAddAcls(new LinkedList<>());
|
||||||
|
@ -133,8 +133,8 @@ public class TestOmAcls {
|
||||||
bucketArgs.setStorageType(StorageType.DISK);
|
bucketArgs.setStorageType(StorageType.DISK);
|
||||||
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
||||||
() -> storageHandler.createBucket(bucketArgs));
|
() -> storageHandler.createBucket(bucketArgs));
|
||||||
assertTrue(logCapturer.getOutput().contains("doesn't have CREATE " +
|
assertTrue(logCapturer.getOutput().contains("Only admin users are" +
|
||||||
"permission to access bucket"));
|
" authorized to create Ozone"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -157,8 +157,8 @@ public class TestOmAcls {
|
||||||
KeyArgs keyArgs = new KeyArgs(keyName, bucketArgs);
|
KeyArgs keyArgs = new KeyArgs(keyName, bucketArgs);
|
||||||
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
OzoneTestUtils.expectOmException(ResultCodes.PERMISSION_DENIED,
|
||||||
() -> storageHandler.newKeyWriter(keyArgs));
|
() -> storageHandler.newKeyWriter(keyArgs));
|
||||||
assertTrue(logCapturer.getOutput().contains("doesn't have READ permission" +
|
assertTrue(logCapturer.getOutput().contains("doesn't have WRITE " +
|
||||||
" to access key"));
|
"permission to access key"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.hadoop.ozone.web.handlers.UserArgs;
|
||||||
import org.apache.hadoop.ozone.web.handlers.VolumeArgs;
|
import org.apache.hadoop.ozone.web.handlers.VolumeArgs;
|
||||||
import org.apache.hadoop.ozone.web.interfaces.StorageHandler;
|
import org.apache.hadoop.ozone.web.interfaces.StorageHandler;
|
||||||
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -94,8 +95,9 @@ public class TestOmBlockVersioning {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAllocateCommit() throws Exception {
|
public void testAllocateCommit() throws Exception {
|
||||||
String userName = "user" + RandomStringUtils.randomNumeric(5);
|
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
|
||||||
String adminName = "admin" + RandomStringUtils.randomNumeric(5);
|
String userName = ugi.getUserName();
|
||||||
|
String adminName = ugi.getUserName();
|
||||||
String volumeName = "volume" + RandomStringUtils.randomNumeric(5);
|
String volumeName = "volume" + RandomStringUtils.randomNumeric(5);
|
||||||
String bucketName = "bucket" + RandomStringUtils.randomNumeric(5);
|
String bucketName = "bucket" + RandomStringUtils.randomNumeric(5);
|
||||||
String keyName = "key" + RandomStringUtils.randomNumeric(5);
|
String keyName = "key" + RandomStringUtils.randomNumeric(5);
|
||||||
|
|
|
@ -89,6 +89,8 @@ import org.apache.hadoop.utils.db.TableIterator;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_CLIENT_ADDRESS_KEY;
|
import static org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_CLIENT_ADDRESS_KEY;
|
||||||
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_ENABLED;
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_ENABLED;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS_WILDCARD;
|
||||||
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_OPEN_KEY_EXPIRE_THRESHOLD_SECONDS;
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_OPEN_KEY_EXPIRE_THRESHOLD_SECONDS;
|
||||||
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
|
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
|
||||||
|
@ -135,6 +137,7 @@ public class TestOzoneManager {
|
||||||
omId = UUID.randomUUID().toString();
|
omId = UUID.randomUUID().toString();
|
||||||
conf.setBoolean(OZONE_ACL_ENABLED, true);
|
conf.setBoolean(OZONE_ACL_ENABLED, true);
|
||||||
conf.setInt(OZONE_OPEN_KEY_EXPIRE_THRESHOLD_SECONDS, 2);
|
conf.setInt(OZONE_OPEN_KEY_EXPIRE_THRESHOLD_SECONDS, 2);
|
||||||
|
conf.set(OZONE_ADMINISTRATORS, OZONE_ADMINISTRATORS_WILDCARD);
|
||||||
cluster = MiniOzoneCluster.newBuilder(conf)
|
cluster = MiniOzoneCluster.newBuilder(conf)
|
||||||
.setClusterId(clusterId)
|
.setClusterId(clusterId)
|
||||||
.setScmId(scmId)
|
.setScmId(scmId)
|
||||||
|
@ -356,7 +359,7 @@ public class TestOzoneManager {
|
||||||
// Create a volume and test Volume access for a different user
|
// Create a volume and test Volume access for a different user
|
||||||
@Test
|
@Test
|
||||||
public void testAccessVolume() throws IOException, OzoneException {
|
public void testAccessVolume() throws IOException, OzoneException {
|
||||||
String userName = "user" + RandomStringUtils.randomNumeric(5);
|
String userName = UserGroupInformation.getCurrentUser().getUserName();
|
||||||
String adminName = "admin" + RandomStringUtils.randomNumeric(5);
|
String adminName = "admin" + RandomStringUtils.randomNumeric(5);
|
||||||
String volumeName = "volume" + RandomStringUtils.randomNumeric(5);
|
String volumeName = "volume" + RandomStringUtils.randomNumeric(5);
|
||||||
String[] groupName =
|
String[] groupName =
|
||||||
|
@ -1012,8 +1015,8 @@ public class TestOzoneManager {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListVolumes() throws IOException, OzoneException {
|
public void testListVolumes() throws IOException, OzoneException {
|
||||||
|
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
|
||||||
String user0 = "testListVolumes-user-0";
|
String user0 = ugi.getUserName();
|
||||||
String user1 = "testListVolumes-user-1";
|
String user1 = "testListVolumes-user-1";
|
||||||
String adminUser = "testListVolumes-admin";
|
String adminUser = "testListVolumes-admin";
|
||||||
ListArgs listVolumeArgs;
|
ListArgs listVolumeArgs;
|
||||||
|
@ -1072,9 +1075,7 @@ public class TestOzoneManager {
|
||||||
listVolumeArgs = new ListArgs(userArgs1, null, 100, null);
|
listVolumeArgs = new ListArgs(userArgs1, null, 100, null);
|
||||||
listVolumeArgs.setRootScan(false);
|
listVolumeArgs.setRootScan(false);
|
||||||
volumes = storageHandler.listVolumes(listVolumeArgs);
|
volumes = storageHandler.listVolumes(listVolumeArgs);
|
||||||
Assert.assertEquals(10, volumes.getVolumes().size());
|
Assert.assertEquals(0, volumes.getVolumes().size());
|
||||||
Assert.assertEquals(user1,
|
|
||||||
volumes.getVolumes().get(3).getOwner().getName());
|
|
||||||
|
|
||||||
// Make sure all available fields are returned
|
// Make sure all available fields are returned
|
||||||
final String user0vol4 = "Vol-" + user0 + "-4";
|
final String user0vol4 = "Vol-" + user0 + "-4";
|
||||||
|
|
|
@ -0,0 +1,464 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with this
|
||||||
|
* work for additional information regarding copyright ownership. The ASF
|
||||||
|
* licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.security.acl;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
||||||
|
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
|
||||||
|
import org.apache.hadoop.hdds.scm.TestUtils;
|
||||||
|
import org.apache.hadoop.hdds.scm.container.MockNodeManager;
|
||||||
|
import org.apache.hadoop.hdds.scm.node.NodeManager;
|
||||||
|
import org.apache.hadoop.hdds.scm.server.SCMConfigurator;
|
||||||
|
import org.apache.hadoop.hdds.scm.server.StorageContainerManager;
|
||||||
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
|
import org.apache.hadoop.ozone.om.BucketManagerImpl;
|
||||||
|
import org.apache.hadoop.ozone.om.IOzoneAcl;
|
||||||
|
import org.apache.hadoop.ozone.om.KeyManagerImpl;
|
||||||
|
import org.apache.hadoop.ozone.om.OMMetadataManager;
|
||||||
|
import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
|
||||||
|
import org.apache.hadoop.ozone.om.PrefixManager;
|
||||||
|
import org.apache.hadoop.ozone.om.PrefixManagerImpl;
|
||||||
|
import org.apache.hadoop.ozone.om.VolumeManagerImpl;
|
||||||
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
|
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
|
||||||
|
import org.apache.hadoop.ozone.om.helpers.OmKeyArgs;
|
||||||
|
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
|
||||||
|
import org.apache.hadoop.ozone.om.helpers.OpenKeySession;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_AUTHORIZER_CLASS;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ACL_AUTHORIZER_CLASS_NATIVE;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_ADMINISTRATORS_WILDCARD;
|
||||||
|
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.ANONYMOUS;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.GROUP;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.USER;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType.WORLD;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.ALL;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType.NONE;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.BUCKET;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.KEY;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.PREFIX;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType.VOLUME;
|
||||||
|
import static org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType.OZONE;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for {@link OzoneNativeAuthorizer}.
|
||||||
|
*/
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class TestOzoneNativeAuthorizer {
|
||||||
|
|
||||||
|
private static OzoneConfiguration ozConfig;
|
||||||
|
private String vol;
|
||||||
|
private String buck;
|
||||||
|
private String key;
|
||||||
|
private String prefix;
|
||||||
|
private ACLType parentDirUserAcl;
|
||||||
|
private ACLType parentDirGroupAcl;
|
||||||
|
private boolean expectedAclResult;
|
||||||
|
|
||||||
|
private static KeyManagerImpl keyManager;
|
||||||
|
private static VolumeManagerImpl volumeManager;
|
||||||
|
private static BucketManagerImpl bucketManager;
|
||||||
|
private static PrefixManager prefixManager;
|
||||||
|
private static OMMetadataManager metadataManager;
|
||||||
|
private static OzoneNativeAuthorizer nativeAuthorizer;
|
||||||
|
|
||||||
|
private static StorageContainerManager scm;
|
||||||
|
private static UserGroupInformation ugi;
|
||||||
|
|
||||||
|
private static OzoneObj volObj;
|
||||||
|
private static OzoneObj buckObj;
|
||||||
|
private static OzoneObj keyObj;
|
||||||
|
private static OzoneObj prefixObj;
|
||||||
|
|
||||||
|
@Parameterized.Parameters
|
||||||
|
public static Collection<Object[]> data() {
|
||||||
|
return Arrays.asList(new Object[][]{
|
||||||
|
{"key", "dir1/", ALL, ALL, true},
|
||||||
|
{"file1", "2019/june/01/", ALL, ALL, true},
|
||||||
|
{"file2", "", ALL, ALL, true},
|
||||||
|
{"dir1/dir2/dir4/", "", ALL, ALL, true},
|
||||||
|
{"key", "dir1/", NONE, NONE, false},
|
||||||
|
{"file1", "2019/june/01/", NONE, NONE, false},
|
||||||
|
{"file2", "", NONE, NONE, false},
|
||||||
|
{"dir1/dir2/dir4/", "", NONE, NONE, false}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestOzoneNativeAuthorizer(String keyName, String prefixName,
|
||||||
|
ACLType userRight,
|
||||||
|
ACLType groupRight, boolean expectedResult) throws IOException {
|
||||||
|
int randomInt = RandomUtils.nextInt();
|
||||||
|
vol = "vol" + randomInt;
|
||||||
|
buck = "bucket" + randomInt;
|
||||||
|
key = keyName + randomInt;
|
||||||
|
prefix = prefixName + randomInt + OZONE_URI_DELIMITER;
|
||||||
|
parentDirUserAcl = userRight;
|
||||||
|
parentDirGroupAcl = groupRight;
|
||||||
|
expectedAclResult = expectedResult;
|
||||||
|
|
||||||
|
createVolume(vol);
|
||||||
|
createBucket(vol, buck);
|
||||||
|
createKey(vol, buck, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() throws Exception {
|
||||||
|
ozConfig = new OzoneConfiguration();
|
||||||
|
ozConfig.set(OZONE_ACL_AUTHORIZER_CLASS,
|
||||||
|
OZONE_ACL_AUTHORIZER_CLASS_NATIVE);
|
||||||
|
File dir = GenericTestUtils.getRandomizedTestDir();
|
||||||
|
ozConfig.set(OZONE_METADATA_DIRS, dir.toString());
|
||||||
|
ozConfig.set(OZONE_ADMINISTRATORS, OZONE_ADMINISTRATORS_WILDCARD);
|
||||||
|
|
||||||
|
metadataManager = new OmMetadataManagerImpl(ozConfig);
|
||||||
|
volumeManager = new VolumeManagerImpl(metadataManager, ozConfig);
|
||||||
|
bucketManager = new BucketManagerImpl(metadataManager);
|
||||||
|
prefixManager = new PrefixManagerImpl(metadataManager);
|
||||||
|
|
||||||
|
NodeManager nodeManager = new MockNodeManager(true, 10);
|
||||||
|
SCMConfigurator configurator = new SCMConfigurator();
|
||||||
|
configurator.setScmNodeManager(nodeManager);
|
||||||
|
scm = TestUtils.getScm(ozConfig, configurator);
|
||||||
|
scm.start();
|
||||||
|
scm.exitSafeMode();
|
||||||
|
keyManager =
|
||||||
|
new KeyManagerImpl(scm.getBlockProtocolServer(), metadataManager,
|
||||||
|
ozConfig,
|
||||||
|
"om1", null);
|
||||||
|
|
||||||
|
nativeAuthorizer = new OzoneNativeAuthorizer(volumeManager, bucketManager,
|
||||||
|
keyManager, prefixManager);
|
||||||
|
//keySession.
|
||||||
|
ugi = UserGroupInformation.getCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createKey(String volume,
|
||||||
|
String bucket, String keyName) throws IOException {
|
||||||
|
OmKeyArgs keyArgs = new OmKeyArgs.Builder()
|
||||||
|
.setVolumeName(volume)
|
||||||
|
.setBucketName(bucket)
|
||||||
|
.setKeyName(keyName)
|
||||||
|
.setFactor(HddsProtos.ReplicationFactor.ONE)
|
||||||
|
.setDataSize(0)
|
||||||
|
.setType(HddsProtos.ReplicationType.STAND_ALONE)
|
||||||
|
.setAcls(OzoneUtils.getAclList(ugi.getUserName(), ugi.getGroups(),
|
||||||
|
ALL, ALL))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (keyName.split(OZONE_URI_DELIMITER).length > 1) {
|
||||||
|
keyManager.createDirectory(keyArgs);
|
||||||
|
key = key + OZONE_URI_DELIMITER;
|
||||||
|
} else {
|
||||||
|
OpenKeySession keySession = keyManager.createFile(keyArgs, true, false);
|
||||||
|
keyArgs.setLocationInfoList(
|
||||||
|
keySession.getKeyInfo().getLatestVersionLocations()
|
||||||
|
.getLocationList());
|
||||||
|
keyManager.commitKey(keyArgs, keySession.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
keyObj = new OzoneObjInfo.Builder()
|
||||||
|
.setVolumeName(vol)
|
||||||
|
.setBucketName(buck)
|
||||||
|
.setKeyName(key)
|
||||||
|
.setResType(KEY)
|
||||||
|
.setStoreType(OZONE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBucket(String volumeName, String bucketName)
|
||||||
|
throws IOException {
|
||||||
|
OmBucketInfo bucketInfo = OmBucketInfo.newBuilder()
|
||||||
|
.setVolumeName(volumeName)
|
||||||
|
.setBucketName(bucketName)
|
||||||
|
.build();
|
||||||
|
bucketManager.createBucket(bucketInfo);
|
||||||
|
buckObj = new OzoneObjInfo.Builder()
|
||||||
|
.setVolumeName(vol)
|
||||||
|
.setBucketName(buck)
|
||||||
|
.setResType(BUCKET)
|
||||||
|
.setStoreType(OZONE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createVolume(String volumeName) throws IOException {
|
||||||
|
OmVolumeArgs volumeArgs = OmVolumeArgs.newBuilder()
|
||||||
|
.setVolume(volumeName)
|
||||||
|
.setAdminName("bilbo")
|
||||||
|
.setOwnerName("bilbo")
|
||||||
|
.build();
|
||||||
|
volumeManager.createVolume(volumeArgs);
|
||||||
|
volObj = new OzoneObjInfo.Builder()
|
||||||
|
.setVolumeName(vol)
|
||||||
|
.setResType(VOLUME)
|
||||||
|
.setStoreType(OZONE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAccessForVolume() throws Exception {
|
||||||
|
expectedAclResult = true;
|
||||||
|
resetAclsAndValidateAccess(volObj, USER, volumeManager);
|
||||||
|
resetAclsAndValidateAccess(volObj, GROUP, volumeManager);
|
||||||
|
resetAclsAndValidateAccess(volObj, WORLD, volumeManager);
|
||||||
|
resetAclsAndValidateAccess(volObj, ANONYMOUS, volumeManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAccessForBucket() throws Exception {
|
||||||
|
|
||||||
|
OzoneAcl userAcl = new OzoneAcl(USER, ugi.getUserName(), parentDirUserAcl);
|
||||||
|
OzoneAcl groupAcl = new OzoneAcl(GROUP, ugi.getGroups().size() > 0 ?
|
||||||
|
ugi.getGroups().get(0) : "", parentDirGroupAcl);
|
||||||
|
// Set access for volume.
|
||||||
|
volumeManager.setAcl(volObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
|
||||||
|
resetAclsAndValidateAccess(buckObj, USER, bucketManager);
|
||||||
|
resetAclsAndValidateAccess(buckObj, GROUP, bucketManager);
|
||||||
|
resetAclsAndValidateAccess(buckObj, WORLD, bucketManager);
|
||||||
|
resetAclsAndValidateAccess(buckObj, ANONYMOUS, bucketManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAccessForKey() throws Exception {
|
||||||
|
OzoneAcl userAcl = new OzoneAcl(USER, ugi.getUserName(), parentDirUserAcl);
|
||||||
|
OzoneAcl groupAcl = new OzoneAcl(GROUP, ugi.getGroups().size() > 0 ?
|
||||||
|
ugi.getGroups().get(0) : "", parentDirGroupAcl);
|
||||||
|
// Set access for volume, bucket & prefix.
|
||||||
|
volumeManager.setAcl(volObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
bucketManager.setAcl(buckObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
//prefixManager.setAcl(prefixObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
|
||||||
|
resetAclsAndValidateAccess(keyObj, USER, keyManager);
|
||||||
|
resetAclsAndValidateAccess(keyObj, GROUP, keyManager);
|
||||||
|
resetAclsAndValidateAccess(keyObj, WORLD, keyManager);
|
||||||
|
resetAclsAndValidateAccess(keyObj, ANONYMOUS, keyManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckAccessForPrefix() throws Exception {
|
||||||
|
prefixObj = new OzoneObjInfo.Builder()
|
||||||
|
.setVolumeName(vol)
|
||||||
|
.setBucketName(buck)
|
||||||
|
.setPrefixName(prefix)
|
||||||
|
.setResType(PREFIX)
|
||||||
|
.setStoreType(OZONE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
OzoneAcl userAcl = new OzoneAcl(USER, ugi.getUserName(), parentDirUserAcl);
|
||||||
|
OzoneAcl groupAcl = new OzoneAcl(GROUP, ugi.getGroups().size() > 0 ?
|
||||||
|
ugi.getGroups().get(0) : "", parentDirGroupAcl);
|
||||||
|
// Set access for volume & bucket.
|
||||||
|
volumeManager.setAcl(volObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
bucketManager.setAcl(buckObj, Arrays.asList(userAcl, groupAcl));
|
||||||
|
|
||||||
|
resetAclsAndValidateAccess(prefixObj, USER, prefixManager);
|
||||||
|
resetAclsAndValidateAccess(prefixObj, GROUP, prefixManager);
|
||||||
|
resetAclsAndValidateAccess(prefixObj, WORLD, prefixManager);
|
||||||
|
resetAclsAndValidateAccess(prefixObj, ANONYMOUS, prefixManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetAclsAndValidateAccess(OzoneObj obj,
|
||||||
|
ACLIdentityType accessType, IOzoneAcl aclImplementor)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
List<OzoneAcl> acls;
|
||||||
|
String user = "";
|
||||||
|
String group = "";
|
||||||
|
|
||||||
|
user = ugi.getUserName();
|
||||||
|
if (ugi.getGroups().size() > 0) {
|
||||||
|
group = ugi.getGroups().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestContext.Builder builder = new RequestContext.Builder()
|
||||||
|
.setClientUgi(ugi)
|
||||||
|
.setAclType(accessType);
|
||||||
|
|
||||||
|
// Get all acls.
|
||||||
|
List<ACLType> allAcls = Arrays.stream(ACLType.values()).
|
||||||
|
collect(Collectors.toList());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Reset default acls to an acl.
|
||||||
|
* 2. Test if user/group has access only to it.
|
||||||
|
* 3. Add remaining acls one by one and then test
|
||||||
|
* if user/group has access to them.
|
||||||
|
* */
|
||||||
|
for (ACLType a1 : allAcls) {
|
||||||
|
OzoneAcl newAcl = new OzoneAcl(accessType, getAclName(accessType), a1);
|
||||||
|
|
||||||
|
// Reset acls to only one right.
|
||||||
|
aclImplementor.setAcl(obj, Arrays.asList(newAcl));
|
||||||
|
|
||||||
|
// Fetch current acls and validate.
|
||||||
|
acls = aclImplementor.getAcl(obj);
|
||||||
|
assertTrue(acls.size() == 1);
|
||||||
|
assertTrue(acls.contains(newAcl));
|
||||||
|
|
||||||
|
// Special handling for ALL.
|
||||||
|
if (a1.equals(ALL)) {
|
||||||
|
validateAll(obj, builder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special handling for NONE.
|
||||||
|
if (a1.equals(NONE)) {
|
||||||
|
validateNone(obj, builder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assertEquals("Acl to check:" + a1 + " accessType:" +
|
||||||
|
accessType + " path:" + obj.getPath(),
|
||||||
|
expectedAclResult, nativeAuthorizer.checkAccess(obj,
|
||||||
|
builder.setAclRights(a1).build()));
|
||||||
|
|
||||||
|
List<ACLType> aclsToBeValidated =
|
||||||
|
Arrays.stream(ACLType.values()).collect(Collectors.toList());
|
||||||
|
List<ACLType> aclsToBeAdded =
|
||||||
|
Arrays.stream(ACLType.values()).collect(Collectors.toList());
|
||||||
|
aclsToBeValidated.remove(NONE);
|
||||||
|
aclsToBeValidated.remove(a1);
|
||||||
|
|
||||||
|
aclsToBeAdded.remove(NONE);
|
||||||
|
aclsToBeAdded.remove(ALL);
|
||||||
|
|
||||||
|
// Fetch acls again.
|
||||||
|
for (ACLType a2 : aclsToBeAdded) {
|
||||||
|
if (!a2.equals(a1)) {
|
||||||
|
|
||||||
|
acls = aclImplementor.getAcl(obj);
|
||||||
|
List right = acls.stream().map(a -> a.getAclList()).collect(
|
||||||
|
Collectors.toList());
|
||||||
|
assertFalse("Do not expected client to have " + a2 + " acl. " +
|
||||||
|
"Current acls found:" + right + ". Type:" + accessType + ","
|
||||||
|
+ " name:" + (accessType == USER ? user : group),
|
||||||
|
nativeAuthorizer.checkAccess(obj,
|
||||||
|
builder.setAclRights(a2).build()));
|
||||||
|
|
||||||
|
// Randomize next type.
|
||||||
|
int type = RandomUtils.nextInt(0, 3);
|
||||||
|
ACLIdentityType identityType = ACLIdentityType.values()[type];
|
||||||
|
// Add remaining acls one by one and then check access.
|
||||||
|
OzoneAcl addAcl = new OzoneAcl(identityType,
|
||||||
|
getAclName(identityType), a2);
|
||||||
|
aclImplementor.addAcl(obj, addAcl);
|
||||||
|
|
||||||
|
// Fetch acls again.
|
||||||
|
acls = aclImplementor.getAcl(obj);
|
||||||
|
boolean a2AclFound = false;
|
||||||
|
boolean a1AclFound = false;
|
||||||
|
for (OzoneAcl acl : acls) {
|
||||||
|
if (acl.getAclList().contains(a2)) {
|
||||||
|
a2AclFound = true;
|
||||||
|
}
|
||||||
|
if (acl.getAclList().contains(a1)) {
|
||||||
|
a1AclFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("Current acls :" + acls + ". " +
|
||||||
|
"Type:" + accessType + ", name:" + (accessType == USER ? user
|
||||||
|
: group) + " acl:" + a2, a2AclFound);
|
||||||
|
assertTrue("Expected client to have " + a1 + " acl. Current acls " +
|
||||||
|
"found:" + acls + ". Type:" + accessType +
|
||||||
|
", name:" + (accessType == USER ? user : group), a1AclFound);
|
||||||
|
assertEquals("Current acls " + acls + ". Expect acl:" + a2 +
|
||||||
|
" to be set? " + expectedAclResult + " accessType:"
|
||||||
|
+ accessType, expectedAclResult,
|
||||||
|
nativeAuthorizer.checkAccess(obj,
|
||||||
|
builder.setAclRights(a2).build()));
|
||||||
|
aclsToBeValidated.remove(a2);
|
||||||
|
for (ACLType a3 : aclsToBeValidated) {
|
||||||
|
if (!a3.equals(a1) && !a3.equals(a2)) {
|
||||||
|
assertFalse("User shouldn't have right " + a3 + ". " +
|
||||||
|
"Current acl rights for user:" + a1 + "," + a2,
|
||||||
|
nativeAuthorizer.checkAccess(obj,
|
||||||
|
builder.setAclRights(a3).build()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAclName(ACLIdentityType identityType) {
|
||||||
|
switch (identityType) {
|
||||||
|
case USER:
|
||||||
|
return ugi.getUserName();
|
||||||
|
case GROUP:
|
||||||
|
if (ugi.getGroups().size() > 0) {
|
||||||
|
return ugi.getGroups().get(0);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test acl rights with user/group had ALL acl bit set.
|
||||||
|
* @param obj
|
||||||
|
* @param builder
|
||||||
|
*/
|
||||||
|
private void validateAll(OzoneObj obj, RequestContext.Builder
|
||||||
|
builder) throws OMException {
|
||||||
|
List<ACLType> allAcls = new ArrayList<>(Arrays.asList(ACLType.values()));
|
||||||
|
allAcls.remove(ALL);
|
||||||
|
allAcls.remove(NONE);
|
||||||
|
for (ACLType a : allAcls) {
|
||||||
|
assertEquals("User should have right " + a + ".",
|
||||||
|
nativeAuthorizer.checkAccess(obj,
|
||||||
|
builder.setAclRights(a).build()), expectedAclResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to test acl rights with user/group had NONE acl bit set.
|
||||||
|
* @param obj
|
||||||
|
* @param builder
|
||||||
|
*/
|
||||||
|
private void validateNone(OzoneObj obj, RequestContext.Builder
|
||||||
|
builder) throws OMException {
|
||||||
|
List<ACLType> allAcls = new ArrayList<>(Arrays.asList(ACLType.values()));
|
||||||
|
allAcls.remove(NONE);
|
||||||
|
for (ACLType a : allAcls) {
|
||||||
|
assertFalse("User shouldn't have right " + a + ".",
|
||||||
|
nativeAuthorizer.checkAccess(obj, builder.setAclRights(a).build()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ import org.apache.hadoop.ozone.client.rest.RestClient;
|
||||||
import org.apache.hadoop.ozone.client.rpc.RpcClient;
|
import org.apache.hadoop.ozone.client.rpc.RpcClient;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
|
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
|
||||||
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.test.GenericTestUtils;
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
|
|
||||||
|
@ -232,7 +233,8 @@ public class TestVolume {
|
||||||
clientProtocol.createVolume(volumeName);
|
clientProtocol.createVolume(volumeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<OzoneVolume> ovols = clientProtocol.listVolumes(null, null, 100);
|
List<OzoneVolume> ovols = clientProtocol.listVolumes(
|
||||||
|
UserGroupInformation.getCurrentUser().getUserName(), null, null, 100);
|
||||||
assertTrue(ovols.size() >= 10);
|
assertTrue(ovols.size() >= 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
|
import org.apache.hadoop.ozone.om.helpers.OmBucketArgs;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
|
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
import org.apache.hadoop.util.Time;
|
import org.apache.hadoop.util.Time;
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.apache.hadoop.ozone.OzoneAcl.ZERO_BITSET;
|
import static org.apache.hadoop.ozone.OzoneAcl.ZERO_BITSET;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_FOUND;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_FOUND;
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INTERNAL_ERROR;
|
||||||
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
|
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
|
||||||
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
|
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
|
||||||
/**
|
/**
|
||||||
|
@ -623,4 +626,47 @@ public class BucketManagerImpl implements BucketManager {
|
||||||
metadataManager.getLock().releaseLock(BUCKET_LOCK, volume, bucket);
|
metadataManager.getLock().releaseLock(BUCKET_LOCK, volume, bucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkAccess(OzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException {
|
||||||
|
Objects.requireNonNull(ozObject);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
|
||||||
|
String volume = ozObject.getVolumeName();
|
||||||
|
String bucket = ozObject.getBucketName();
|
||||||
|
metadataManager.getLock().acquireLock(BUCKET_LOCK, volume, bucket);
|
||||||
|
try {
|
||||||
|
String dbBucketKey = metadataManager.getBucketKey(volume, bucket);
|
||||||
|
OmBucketInfo bucketInfo =
|
||||||
|
metadataManager.getBucketTable().get(dbBucketKey);
|
||||||
|
if (bucketInfo == null) {
|
||||||
|
LOG.debug("Bucket:{}/{} does not exist", volume, bucket);
|
||||||
|
throw new OMException("Bucket " + bucket + " is not found",
|
||||||
|
BUCKET_NOT_FOUND);
|
||||||
|
}
|
||||||
|
boolean hasAccess = OzoneUtils.checkAclRights(bucketInfo.getAcls(),
|
||||||
|
context);
|
||||||
|
LOG.debug("user:{} has access rights for bucket:{} :{} ",
|
||||||
|
context.getClientUgi(), ozObject.getBucketName(), hasAccess);
|
||||||
|
return hasAccess;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
if(ex instanceof OMException) {
|
||||||
|
throw (OMException) ex;
|
||||||
|
}
|
||||||
|
LOG.error("CheckAccess operation failed for bucket:{}/{} acl:{}",
|
||||||
|
volume, bucket, ex);
|
||||||
|
throw new OMException("Check access operation failed for " +
|
||||||
|
"bucket:" + bucket, ex, INTERNAL_ERROR);
|
||||||
|
} finally {
|
||||||
|
metadataManager.getLock().releaseLock(BUCKET_LOCK, volume, bucket);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
package org.apache.hadoop.ozone.om;
|
package org.apache.hadoop.ozone.om;
|
||||||
|
|
||||||
import org.apache.hadoop.ozone.OzoneAcl;
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -64,4 +66,15 @@ public interface IOzoneAcl {
|
||||||
* @throws IOException if there is error.
|
* @throws IOException if there is error.
|
||||||
* */
|
* */
|
||||||
List<OzoneAcl> getAcl(OzoneObj obj) throws IOException;
|
List<OzoneAcl> getAcl(OzoneObj obj) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @throws org.apache.hadoop.ozone.om.exceptions.OMException
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
boolean checkAccess(OzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* Handles key level commands.
|
* Handles key level commands.
|
||||||
*/
|
*/
|
||||||
public interface KeyManager extends OzoneManagerFS {
|
public interface KeyManager extends OzoneManagerFS, IOzoneAcl {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start key manager.
|
* Start key manager.
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.BitSet;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -35,11 +36,11 @@ import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
import org.apache.commons.codec.digest.DigestUtils;
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.hadoop.conf.StorageUnit;
|
import org.apache.hadoop.conf.StorageUnit;
|
||||||
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
|
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
|
||||||
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension.EncryptedKeyVersion;
|
import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension.EncryptedKeyVersion;
|
||||||
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
|
||||||
import org.apache.hadoop.fs.FileEncryptionInfo;
|
import org.apache.hadoop.fs.FileEncryptionInfo;
|
||||||
import org.apache.hadoop.hdds.client.BlockID;
|
import org.apache.hadoop.hdds.client.BlockID;
|
||||||
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
||||||
|
@ -79,10 +80,10 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
|
||||||
.KeyLocation;
|
.KeyLocation;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo.OzoneAclRights;
|
|
||||||
import org.apache.hadoop.ozone.security.OzoneBlockTokenSecretManager;
|
import org.apache.hadoop.ozone.security.OzoneBlockTokenSecretManager;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
|
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
import org.apache.hadoop.security.SecurityUtil;
|
import org.apache.hadoop.security.SecurityUtil;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.ozone.common.BlockGroup;
|
import org.apache.hadoop.ozone.common.BlockGroup;
|
||||||
|
@ -102,6 +103,7 @@ import org.apache.hadoop.utils.db.Table;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.HADOOP_SECURITY_KEY_PROVIDER_PATH;
|
||||||
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED;
|
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED;
|
||||||
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED_DEFAULT;
|
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED_DEFAULT;
|
||||||
import static org.apache.hadoop.ozone.OzoneConfigKeys.DFS_CONTAINER_RATIS_ENABLED_DEFAULT;
|
import static org.apache.hadoop.ozone.OzoneConfigKeys.DFS_CONTAINER_RATIS_ENABLED_DEFAULT;
|
||||||
|
@ -117,6 +119,10 @@ import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SCM_BLOCK_SIZE_DEFAU
|
||||||
import static org.apache.hadoop.ozone.OzoneConsts.OM_MULTIPART_MIN_SIZE;
|
import static org.apache.hadoop.ozone.OzoneConsts.OM_MULTIPART_MIN_SIZE;
|
||||||
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
|
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_FOUND;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_FOUND;
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.DIRECTORY_NOT_FOUND;
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INTERNAL_ERROR;
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_KMS_PROVIDER;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_NOT_FOUND;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_NOT_FOUND;
|
||||||
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
|
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
|
||||||
|
@ -1402,15 +1408,13 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
OzoneAclInfo newAcl = null;
|
OzoneAclInfo newAcl = null;
|
||||||
for(OzoneAclInfo a: keyInfo.getAcls()) {
|
for(OzoneAclInfo a: keyInfo.getAcls()) {
|
||||||
if(a.getName().equals(acl.getName())) {
|
if(a.getName().equals(acl.getName())) {
|
||||||
List<OzoneAclRights> rights =
|
BitSet currentAcls = BitSet.valueOf(a.getRights().toByteArray());
|
||||||
new ArrayList<>(a.getRightsList());
|
currentAcls.or(acl.getAclBitSet());
|
||||||
for (IAccessAuthorizer.ACLType aclType : acl.getAclList()) {
|
|
||||||
rights.add(OzoneAclRights.valueOf(aclType.name()));
|
|
||||||
}
|
|
||||||
newAcl = OzoneAclInfo.newBuilder()
|
newAcl = OzoneAclInfo.newBuilder()
|
||||||
.setType(a.getType())
|
.setType(a.getType())
|
||||||
.setName(a.getName())
|
.setName(a.getName())
|
||||||
.addAllRights(rights)
|
.setRights(ByteString.copyFrom(currentAcls.toByteArray()))
|
||||||
.build();
|
.build();
|
||||||
newAcls.remove(a);
|
newAcls.remove(a);
|
||||||
newAcls.add(newAcl);
|
newAcls.add(newAcl);
|
||||||
|
@ -1488,15 +1492,13 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
// Acl to be removed might be a subset of existing acls.
|
// Acl to be removed might be a subset of existing acls.
|
||||||
for(OzoneAclInfo a: keyInfo.getAcls()) {
|
for(OzoneAclInfo a: keyInfo.getAcls()) {
|
||||||
if(a.getName().equals(acl.getName())) {
|
if(a.getName().equals(acl.getName())) {
|
||||||
List<OzoneAclRights> rights =
|
BitSet currentAcls = BitSet.valueOf(a.getRights().toByteArray());
|
||||||
new ArrayList<>(a.getRightsList());
|
acl.getAclBitSet().xor(currentAcls);
|
||||||
for (IAccessAuthorizer.ACLType aclType : acl.getAclList()) {
|
currentAcls.and(acl.getAclBitSet());
|
||||||
rights.remove(OzoneAclRights.valueOf(aclType.name()));
|
|
||||||
}
|
|
||||||
newAcl = OzoneAclInfo.newBuilder()
|
newAcl = OzoneAclInfo.newBuilder()
|
||||||
.setType(a.getType())
|
.setType(a.getType())
|
||||||
.setName(a.getName())
|
.setName(a.getName())
|
||||||
.addAllRights(rights)
|
.setRights(ByteString.copyFrom(currentAcls.toByteArray()))
|
||||||
.build();
|
.build();
|
||||||
newAcls.remove(a);
|
newAcls.remove(a);
|
||||||
newAcls.add(newAcl);
|
newAcls.add(newAcl);
|
||||||
|
@ -1640,6 +1642,58 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkAccess(OzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException {
|
||||||
|
Objects.requireNonNull(ozObject);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
Objects.requireNonNull(context.getClientUgi());
|
||||||
|
|
||||||
|
String volume = ozObject.getVolumeName();
|
||||||
|
String bucket = ozObject.getBucketName();
|
||||||
|
String keyName = ozObject.getKeyName();
|
||||||
|
|
||||||
|
metadataManager.getLock().acquireLock(BUCKET_LOCK, volume, bucket);
|
||||||
|
try {
|
||||||
|
validateBucket(volume, bucket);
|
||||||
|
String objectKey = metadataManager.getOzoneKey(volume, bucket, keyName);
|
||||||
|
OmKeyInfo keyInfo = metadataManager.getKeyTable().get(objectKey);
|
||||||
|
if (keyInfo == null) {
|
||||||
|
objectKey = OzoneFSUtils.addTrailingSlashIfNeeded(objectKey);
|
||||||
|
keyInfo = metadataManager.getKeyTable().get(objectKey);
|
||||||
|
|
||||||
|
if(keyInfo == null) {
|
||||||
|
keyInfo = metadataManager.getOpenKeyTable().get(objectKey);
|
||||||
|
if (keyInfo == null) {
|
||||||
|
throw new OMException("Key not found, checkAccess failed. Key:" +
|
||||||
|
objectKey, KEY_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean hasAccess = OzoneUtils.checkAclRight(keyInfo.getAcls(), context);
|
||||||
|
LOG.debug("user:{} has access rights for key:{} :{} ",
|
||||||
|
context.getClientUgi(), ozObject.getKeyName(), hasAccess);
|
||||||
|
return hasAccess;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
if(ex instanceof OMException) {
|
||||||
|
throw (OMException) ex;
|
||||||
|
}
|
||||||
|
LOG.error("CheckAccess operation failed for key:{}/{}/{}", volume,
|
||||||
|
bucket, keyName, ex);
|
||||||
|
throw new OMException("Check access operation failed for " +
|
||||||
|
"key:" + keyName, ex, INTERNAL_ERROR);
|
||||||
|
} finally {
|
||||||
|
metadataManager.getLock().releaseLock(BUCKET_LOCK, volume, bucket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to validate ozone object.
|
* Helper method to validate ozone object.
|
||||||
* @param obj
|
* @param obj
|
||||||
|
@ -1717,7 +1771,7 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
"such file exists:");
|
"such file exists:");
|
||||||
throw new OMException("Unable to get file status: volume: " +
|
throw new OMException("Unable to get file status: volume: " +
|
||||||
volumeName + " bucket: " + bucketName + " key: " + keyName,
|
volumeName + " bucket: " + bucketName + " key: " + keyName,
|
||||||
ResultCodes.FILE_NOT_FOUND);
|
FILE_NOT_FOUND);
|
||||||
} finally {
|
} finally {
|
||||||
metadataManager.getLock().releaseLock(BUCKET_LOCK, volumeName,
|
metadataManager.getLock().releaseLock(BUCKET_LOCK, volumeName,
|
||||||
bucketName);
|
bucketName);
|
||||||
|
@ -1830,7 +1884,7 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (OMException ex) {
|
} catch (OMException ex) {
|
||||||
if (ex.getResult() != ResultCodes.FILE_NOT_FOUND) {
|
if (ex.getResult() != FILE_NOT_FOUND) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2022,12 +2076,12 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
return fileStatus;
|
return fileStatus;
|
||||||
}
|
}
|
||||||
} catch (OMException ex) {
|
} catch (OMException ex) {
|
||||||
if (ex.getResult() != ResultCodes.FILE_NOT_FOUND) {
|
if (ex.getResult() != FILE_NOT_FOUND) {
|
||||||
throw ex;
|
throw ex;
|
||||||
} else if (ex.getResult() == ResultCodes.FILE_NOT_FOUND) {
|
} else if (ex.getResult() == FILE_NOT_FOUND) {
|
||||||
if (directoryMustExist) {
|
if (directoryMustExist) {
|
||||||
throw new OMException("Parent directory does not exist",
|
throw new OMException("Parent directory does not exist",
|
||||||
ex.getCause(), ResultCodes.DIRECTORY_NOT_FOUND);
|
ex.getCause(), DIRECTORY_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2043,8 +2097,8 @@ public class KeyManagerImpl implements KeyManager {
|
||||||
if (ezInfo != null) {
|
if (ezInfo != null) {
|
||||||
if (getKMSProvider() == null) {
|
if (getKMSProvider() == null) {
|
||||||
throw new OMException("Invalid KMS provider, check configuration " +
|
throw new OMException("Invalid KMS provider, check configuration " +
|
||||||
CommonConfigurationKeys.HADOOP_SECURITY_KEY_PROVIDER_PATH,
|
HADOOP_SECURITY_KEY_PROVIDER_PATH,
|
||||||
OMException.ResultCodes.INVALID_KMS_PROVIDER);
|
INVALID_KMS_PROVIDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String ezKeyName = ezInfo.getKeyName();
|
final String ezKeyName = ezInfo.getKeyName();
|
||||||
|
|
|
@ -32,6 +32,7 @@ import java.security.cert.CertificateException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.conf.StorageUnit;
|
import org.apache.hadoop.conf.StorageUnit;
|
||||||
import org.apache.hadoop.crypto.key.KeyProvider;
|
import org.apache.hadoop.crypto.key.KeyProvider;
|
||||||
|
@ -72,6 +73,7 @@ import org.apache.hadoop.ipc.ProtobufRpcEngine;
|
||||||
import org.apache.hadoop.ipc.RPC;
|
import org.apache.hadoop.ipc.RPC;
|
||||||
import org.apache.hadoop.ipc.Server;
|
import org.apache.hadoop.ipc.Server;
|
||||||
import org.apache.hadoop.ozone.OzoneAcl;
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
|
import org.apache.hadoop.ozone.OzoneConfigKeys;
|
||||||
import org.apache.hadoop.ozone.OzoneIllegalArgumentException;
|
import org.apache.hadoop.ozone.OzoneIllegalArgumentException;
|
||||||
import org.apache.hadoop.ozone.OzoneSecurityUtil;
|
import org.apache.hadoop.ozone.OzoneSecurityUtil;
|
||||||
import org.apache.hadoop.ozone.om.ha.OMFailoverProxyProvider;
|
import org.apache.hadoop.ozone.om.ha.OMFailoverProxyProvider;
|
||||||
|
@ -102,7 +104,6 @@ import org.apache.hadoop.ozone.audit.AuditLoggerType;
|
||||||
import org.apache.hadoop.ozone.audit.AuditMessage;
|
import org.apache.hadoop.ozone.audit.AuditMessage;
|
||||||
import org.apache.hadoop.ozone.audit.Auditor;
|
import org.apache.hadoop.ozone.audit.Auditor;
|
||||||
import org.apache.hadoop.ozone.audit.OMAction;
|
import org.apache.hadoop.ozone.audit.OMAction;
|
||||||
import org.apache.hadoop.ozone.OzoneConfigKeys;
|
|
||||||
import org.apache.hadoop.ozone.common.Storage.StorageState;
|
import org.apache.hadoop.ozone.common.Storage.StorageState;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
|
import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
|
||||||
|
@ -130,6 +131,7 @@ import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
|
||||||
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneAccessAuthorizer;
|
import org.apache.hadoop.ozone.security.acl.OzoneAccessAuthorizer;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.OzoneNativeAuthorizer;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj.StoreType;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj.ResourceType;
|
||||||
|
@ -209,6 +211,8 @@ import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_USER_MAX_VOLUME;
|
||||||
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_USER_MAX_VOLUME_DEFAULT;
|
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_USER_MAX_VOLUME_DEFAULT;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_AUTH_METHOD;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_AUTH_METHOD;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
|
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.OzoneConfigKeys.OZONE_ADMINISTRATORS_WILDCARD;
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_ERROR_OTHER;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.TOKEN_ERROR_OTHER;
|
||||||
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.S3_BUCKET_LOCK;
|
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.S3_BUCKET_LOCK;
|
||||||
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
|
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_LOCK;
|
||||||
|
@ -277,6 +281,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
private File omRatisSnapshotDir;
|
private File omRatisSnapshotDir;
|
||||||
private final File ratisSnapshotFile;
|
private final File ratisSnapshotFile;
|
||||||
private long snapshotIndex;
|
private long snapshotIndex;
|
||||||
|
private final Collection<String> ozAdmins;
|
||||||
|
|
||||||
private KeyProviderCryptoExtension kmsProvider = null;
|
private KeyProviderCryptoExtension kmsProvider = null;
|
||||||
private static String keyProviderUriKeyName =
|
private static String keyProviderUriKeyName =
|
||||||
|
@ -341,7 +346,6 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
OMConfigKeys.OZONE_OM_RATIS_ENABLE_DEFAULT);
|
OMConfigKeys.OZONE_OM_RATIS_ENABLE_DEFAULT);
|
||||||
startRatisServer();
|
startRatisServer();
|
||||||
startRatisClient();
|
startRatisClient();
|
||||||
|
|
||||||
if (isRatisEnabled) {
|
if (isRatisEnabled) {
|
||||||
// Create Ratis storage dir
|
// Create Ratis storage dir
|
||||||
String omRatisDirectory = OmUtils.getOMRatisDirectory(configuration);
|
String omRatisDirectory = OmUtils.getOMRatisDirectory(configuration);
|
||||||
|
@ -350,7 +354,6 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
" must be defined.");
|
" must be defined.");
|
||||||
}
|
}
|
||||||
OmUtils.createOMDir(omRatisDirectory);
|
OmUtils.createOMDir(omRatisDirectory);
|
||||||
|
|
||||||
// Create Ratis snapshot dir
|
// Create Ratis snapshot dir
|
||||||
omRatisSnapshotDir = OmUtils.createOMDir(
|
omRatisSnapshotDir = OmUtils.createOMDir(
|
||||||
OmUtils.getOMRatisSnapshotDirectory(configuration));
|
OmUtils.getOMRatisSnapshotDirectory(configuration));
|
||||||
|
@ -367,9 +370,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
|
|
||||||
InetSocketAddress omNodeRpcAddr = omNodeDetails.getRpcAddress();
|
InetSocketAddress omNodeRpcAddr = omNodeDetails.getRpcAddress();
|
||||||
omRpcAddressTxt = new Text(omNodeDetails.getRpcAddressString());
|
omRpcAddressTxt = new Text(omNodeDetails.getRpcAddressString());
|
||||||
|
|
||||||
secConfig = new SecurityConfig(configuration);
|
secConfig = new SecurityConfig(configuration);
|
||||||
|
|
||||||
volumeManager = new VolumeManagerImpl(metadataManager, configuration);
|
volumeManager = new VolumeManagerImpl(metadataManager, configuration);
|
||||||
|
|
||||||
// Create the KMS Key Provider
|
// Create the KMS Key Provider
|
||||||
|
@ -407,9 +408,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
this.scmClient = new ScmClient(scmBlockClient, scmContainerClient);
|
this.scmClient = new ScmClient(scmBlockClient, scmContainerClient);
|
||||||
keyManager = new KeyManagerImpl(scmClient, metadataManager,
|
keyManager = new KeyManagerImpl(scmClient, metadataManager,
|
||||||
configuration, omStorage.getOmId(), blockTokenMgr, getKmsProvider());
|
configuration, omStorage.getOmId(), blockTokenMgr, getKmsProvider());
|
||||||
|
|
||||||
prefixManager = new PrefixManagerImpl(metadataManager);
|
prefixManager = new PrefixManagerImpl(metadataManager);
|
||||||
|
|
||||||
shutdownHook = () -> {
|
shutdownHook = () -> {
|
||||||
saveOmMetrics();
|
saveOmMetrics();
|
||||||
};
|
};
|
||||||
|
@ -419,9 +418,19 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
OZONE_ACL_ENABLED_DEFAULT);
|
OZONE_ACL_ENABLED_DEFAULT);
|
||||||
if (isAclEnabled) {
|
if (isAclEnabled) {
|
||||||
accessAuthorizer = getACLAuthorizerInstance(conf);
|
accessAuthorizer = getACLAuthorizerInstance(conf);
|
||||||
|
if (accessAuthorizer instanceof OzoneNativeAuthorizer) {
|
||||||
|
OzoneNativeAuthorizer authorizer =
|
||||||
|
(OzoneNativeAuthorizer) accessAuthorizer;
|
||||||
|
authorizer.setVolumeManager(volumeManager);
|
||||||
|
authorizer.setBucketManager(bucketManager);
|
||||||
|
authorizer.setKeyManager(keyManager);
|
||||||
|
authorizer.setPrefixManager(prefixManager);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
accessAuthorizer = null;
|
accessAuthorizer = null;
|
||||||
}
|
}
|
||||||
|
ozAdmins = conf.getTrimmedStringCollection(OzoneConfigKeys
|
||||||
|
.OZONE_ADMINISTRATORS);
|
||||||
omMetaDir = OmUtils.getOmDbDir(configuration);
|
omMetaDir = OmUtils.getOmDbDir(configuration);
|
||||||
|
|
||||||
this.scmBlockSize = (long) conf
|
this.scmBlockSize = (long) conf
|
||||||
|
@ -1676,8 +1685,14 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public void createVolume(OmVolumeArgs args) throws IOException {
|
public void createVolume(OmVolumeArgs args) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.VOLUME, StoreType.OZONE,
|
if (!ozAdmins.contains(OZONE_ADMINISTRATORS_WILDCARD) &&
|
||||||
ACLType.CREATE, args.getVolume(), null, null);
|
!ozAdmins.contains(ProtobufRpcEngine.Server.getRemoteUser()
|
||||||
|
.getUserName())) {
|
||||||
|
LOG.error("Only admin users are authorized to create " +
|
||||||
|
"Ozone volumes.");
|
||||||
|
throw new OMException("Only admin users are authorized to create " +
|
||||||
|
"Ozone volumes.", ResultCodes.PERMISSION_DENIED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
metrics.incNumVolumeCreates();
|
metrics.incNumVolumeCreates();
|
||||||
volumeManager.createVolume(args);
|
volumeManager.createVolume(args);
|
||||||
|
@ -2003,8 +2018,13 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public List<OmVolumeArgs> listVolumeByUser(String userName, String prefix,
|
public List<OmVolumeArgs> listVolumeByUser(String userName, String prefix,
|
||||||
String prevKey, int maxKeys) throws IOException {
|
String prevKey, int maxKeys) throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.VOLUME, StoreType.OZONE, ACLType.LIST, prefix,
|
UserGroupInformation remoteUserUgi = ProtobufRpcEngine.Server.
|
||||||
null, null);
|
getRemoteUser();
|
||||||
|
if (remoteUserUgi == null) {
|
||||||
|
LOG.error("Rpc user UGI is null. Authorization failed.");
|
||||||
|
throw new OMException("Rpc user UGI is null. Authorization " +
|
||||||
|
"failed.", ResultCodes.PERMISSION_DENIED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
Map<String, String> auditMap = new LinkedHashMap<>();
|
Map<String, String> auditMap = new LinkedHashMap<>();
|
||||||
|
@ -2043,8 +2063,14 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public List<OmVolumeArgs> listAllVolumes(String prefix, String prevKey, int
|
public List<OmVolumeArgs> listAllVolumes(String prefix, String prevKey, int
|
||||||
maxKeys) throws IOException {
|
maxKeys) throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.VOLUME, StoreType.OZONE, ACLType.LIST, prefix,
|
if (!ozAdmins.contains(ProtobufRpcEngine.Server.
|
||||||
null, null);
|
getRemoteUser().getUserName())
|
||||||
|
&& !ozAdmins.contains(OZONE_ADMINISTRATORS_WILDCARD)) {
|
||||||
|
LOG.error("Only admin users are authorized to create " +
|
||||||
|
"Ozone volumes.");
|
||||||
|
throw new OMException("Only admin users are authorized to create " +
|
||||||
|
"Ozone volumes.", ResultCodes.PERMISSION_DENIED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
Map<String, String> auditMap = new LinkedHashMap<>();
|
Map<String, String> auditMap = new LinkedHashMap<>();
|
||||||
|
@ -2079,7 +2105,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public void createBucket(OmBucketInfo bucketInfo) throws IOException {
|
public void createBucket(OmBucketInfo bucketInfo) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.CREATE,
|
checkAcls(ResourceType.VOLUME, StoreType.OZONE, ACLType.CREATE,
|
||||||
bucketInfo.getVolumeName(), bucketInfo.getBucketName(), null);
|
bucketInfo.getVolumeName(), bucketInfo.getBucketName(), null);
|
||||||
}
|
}
|
||||||
metrics.incNumBucketCreates();
|
metrics.incNumBucketCreates();
|
||||||
|
@ -2175,8 +2201,19 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
@Override
|
@Override
|
||||||
public OpenKeySession openKey(OmKeyArgs args) throws IOException {
|
public OpenKeySession openKey(OmKeyArgs args) throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.READ,
|
try {
|
||||||
|
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} catch (OMException ex) {
|
||||||
|
// For new keys key checkAccess call will fail as key doesn't exist.
|
||||||
|
// Check user access for bucket.
|
||||||
|
if (ex.getResult().equals(KEY_NOT_FOUND)) {
|
||||||
|
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.WRITE,
|
||||||
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
try {
|
try {
|
||||||
|
@ -2245,8 +2282,19 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public void commitKey(OmKeyArgs args, long clientID)
|
public void commitKey(OmKeyArgs args, long clientID)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
|
try {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} catch (OMException ex) {
|
||||||
|
// For new keys key checkAccess call will fail as key doesn't exist.
|
||||||
|
// Check user access for bucket.
|
||||||
|
if (ex.getResult().equals(KEY_NOT_FOUND)) {
|
||||||
|
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.WRITE,
|
||||||
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Map<String, String> auditMap = (args == null) ? new LinkedHashMap<>() :
|
Map<String, String> auditMap = (args == null) ? new LinkedHashMap<>() :
|
||||||
args.toAuditMap();
|
args.toAuditMap();
|
||||||
|
@ -2276,11 +2324,21 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OmKeyLocationInfo allocateBlock(OmKeyArgs args, long clientID,
|
public OmKeyLocationInfo allocateBlock(OmKeyArgs args, long clientID,
|
||||||
ExcludeList excludeList)
|
ExcludeList excludeList) throws IOException {
|
||||||
throws IOException {
|
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
|
try {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} catch (OMException ex) {
|
||||||
|
// For new keys key checkAccess call will fail as key doesn't exist.
|
||||||
|
// Check user access for bucket.
|
||||||
|
if (ex.getResult().equals(KEY_NOT_FOUND)) {
|
||||||
|
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.WRITE,
|
||||||
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
|
} else {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
Map<String, String> auditMap = (args == null) ? new LinkedHashMap<>() :
|
Map<String, String> auditMap = (args == null) ? new LinkedHashMap<>() :
|
||||||
|
@ -2414,8 +2472,8 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public List<OmKeyInfo> listKeys(String volumeName, String bucketName,
|
public List<OmKeyInfo> listKeys(String volumeName, String bucketName,
|
||||||
String startKey, String keyPrefix, int maxKeys) throws IOException {
|
String startKey, String keyPrefix, int maxKeys) throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.LIST, volumeName,
|
checkAcls(ResourceType.BUCKET,
|
||||||
bucketName, keyPrefix);
|
StoreType.OZONE, ACLType.LIST, volumeName, bucketName, keyPrefix);
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
Map<String, String> auditMap = buildAuditMap(volumeName);
|
Map<String, String> auditMap = buildAuditMap(volumeName);
|
||||||
|
@ -2645,10 +2703,6 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
boolean acquiredS3Lock = false;
|
boolean acquiredS3Lock = false;
|
||||||
boolean acquiredVolumeLock = false;
|
boolean acquiredVolumeLock = false;
|
||||||
try {
|
try {
|
||||||
if(isAclEnabled) {
|
|
||||||
checkAcls(ResourceType.BUCKET, StoreType.S3, ACLType.CREATE,
|
|
||||||
null, s3BucketName, null);
|
|
||||||
}
|
|
||||||
metrics.incNumBucketCreates();
|
metrics.incNumBucketCreates();
|
||||||
acquiredS3Lock = metadataManager.getLock().acquireLock(S3_BUCKET_LOCK,
|
acquiredS3Lock = metadataManager.getLock().acquireLock(S3_BUCKET_LOCK,
|
||||||
s3BucketName);
|
s3BucketName);
|
||||||
|
@ -2692,8 +2746,8 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public void deleteS3Bucket(String s3BucketName) throws IOException {
|
public void deleteS3Bucket(String s3BucketName) throws IOException {
|
||||||
try {
|
try {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.BUCKET, StoreType.S3, ACLType.DELETE, null,
|
checkAcls(ResourceType.BUCKET, StoreType.S3, ACLType.DELETE,
|
||||||
s3BucketName, null);
|
getS3VolumeName(), s3BucketName, null);
|
||||||
}
|
}
|
||||||
metrics.incNumBucketDeletes();
|
metrics.incNumBucketDeletes();
|
||||||
s3BucketManager.deleteS3Bucket(s3BucketName);
|
s3BucketManager.deleteS3Bucket(s3BucketName);
|
||||||
|
@ -2719,11 +2773,19 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.BUCKET, StoreType.S3, ACLType.READ,
|
checkAcls(ResourceType.BUCKET, StoreType.S3, ACLType.READ,
|
||||||
null, s3BucketName, null);
|
getS3VolumeName(), s3BucketName, null);
|
||||||
}
|
}
|
||||||
return s3BucketManager.getOzoneBucketMapping(s3BucketName);
|
return s3BucketManager.getOzoneBucketMapping(s3BucketName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to return volume name for S3 users.
|
||||||
|
* */
|
||||||
|
private String getS3VolumeName() {
|
||||||
|
return s3BucketManager.formatOzoneVolumeName(DigestUtils.md5Hex(
|
||||||
|
ProtobufRpcEngine.Server.getRemoteUser().getUserName().toLowerCase()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OmBucketInfo> listS3Buckets(String userName, String startKey,
|
public List<OmBucketInfo> listS3Buckets(String userName, String startKey,
|
||||||
String prefix, int maxNumOfBuckets)
|
String prefix, int maxNumOfBuckets)
|
||||||
|
@ -2900,7 +2962,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
@Override
|
@Override
|
||||||
public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {
|
public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {
|
||||||
if (isAclEnabled) {
|
if (isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.READ,
|
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.READ,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
|
@ -2923,10 +2985,17 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceType getResourceType(OmKeyArgs args) {
|
||||||
|
if (args.getKeyName() == null || args.getKeyName().length() == 0) {
|
||||||
|
return ResourceType.BUCKET;
|
||||||
|
}
|
||||||
|
return ResourceType.KEY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createDirectory(OmKeyArgs args) throws IOException {
|
public void createDirectory(OmKeyArgs args) throws IOException {
|
||||||
if (isAclEnabled) {
|
if (isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.WRITE,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
|
@ -2953,8 +3022,8 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public OpenKeySession createFile(OmKeyArgs args, boolean overWrite,
|
public OpenKeySession createFile(OmKeyArgs args, boolean overWrite,
|
||||||
boolean recursive) throws IOException {
|
boolean recursive) throws IOException {
|
||||||
if (isAclEnabled) {
|
if (isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.WRITE,
|
checkAcls(ResourceType.BUCKET, StoreType.OZONE, ACLType.WRITE,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), null);
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
try {
|
try {
|
||||||
|
@ -3002,7 +3071,7 @@ public final class OzoneManager extends ServiceRuntimeInfoImpl
|
||||||
public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
|
public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
|
||||||
String startKey, long numEntries) throws IOException {
|
String startKey, long numEntries) throws IOException {
|
||||||
if(isAclEnabled) {
|
if(isAclEnabled) {
|
||||||
checkAcls(ResourceType.KEY, StoreType.OZONE, ACLType.READ,
|
checkAcls(getResourceType(args), StoreType.OZONE, ACLType.READ,
|
||||||
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
args.getVolumeName(), args.getBucketName(), args.getKeyName());
|
||||||
}
|
}
|
||||||
boolean auditSuccess = true;
|
boolean auditSuccess = true;
|
||||||
|
|
|
@ -21,8 +21,10 @@ import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmPrefixInfo;
|
import org.apache.hadoop.ozone.om.helpers.OmPrefixInfo;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
import org.apache.hadoop.ozone.util.RadixNode;
|
import org.apache.hadoop.ozone.util.RadixNode;
|
||||||
import org.apache.hadoop.ozone.util.RadixTree;
|
import org.apache.hadoop.ozone.util.RadixTree;
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
|
||||||
import org.apache.hadoop.utils.db.*;
|
import org.apache.hadoop.utils.db.*;
|
||||||
import org.apache.hadoop.utils.db.Table.KeyValue;
|
import org.apache.hadoop.utils.db.Table.KeyValue;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -273,6 +275,43 @@ public class PrefixManagerImpl implements PrefixManager {
|
||||||
return EMPTY_ACL_LIST;
|
return EMPTY_ACL_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkAccess(OzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException {
|
||||||
|
Objects.requireNonNull(ozObject);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
|
||||||
|
String prefixPath = ozObject.getPath();
|
||||||
|
metadataManager.getLock().acquireLock(PREFIX_LOCK, prefixPath);
|
||||||
|
try {
|
||||||
|
String longestPrefix = prefixTree.getLongestPrefix(prefixPath);
|
||||||
|
if (prefixPath.equals(longestPrefix)) {
|
||||||
|
RadixNode<OmPrefixInfo> lastNode =
|
||||||
|
prefixTree.getLastNodeInPrefixPath(prefixPath);
|
||||||
|
if (lastNode != null && lastNode.getValue() != null) {
|
||||||
|
boolean hasAccess = OzoneUtils.checkAclRights(lastNode.getValue().
|
||||||
|
getAcls(), context);
|
||||||
|
LOG.debug("user:{} has access rights for ozObj:{} ::{} ",
|
||||||
|
context.getClientUgi(), ozObject, hasAccess);
|
||||||
|
return hasAccess;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
metadataManager.getLock().releaseLock(PREFIX_LOCK, prefixPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<OmPrefixInfo> getLongestPrefixPath(String path) {
|
public List<OmPrefixInfo> getLongestPrefixPath(String path) {
|
||||||
String prefixPath = prefixTree.getLongestPrefix(path);
|
String prefixPath = prefixTree.getLongestPrefix(path);
|
||||||
|
|
|
@ -21,10 +21,13 @@ package org.apache.hadoop.ozone.om;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
||||||
import org.apache.hadoop.hdds.protocol.StorageType;
|
import org.apache.hadoop.hdds.protocol.StorageType;
|
||||||
|
import org.apache.hadoop.ipc.ProtobufRpcEngine;
|
||||||
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
import org.apache.hadoop.ozone.OzoneConsts;
|
import org.apache.hadoop.ozone.OzoneConsts;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
|
import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
|
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
|
||||||
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_ALREADY_EXISTS;
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_ALREADY_EXISTS;
|
||||||
|
|
||||||
|
@ -33,6 +36,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.apache.hadoop.ozone.OzoneConsts.OM_S3_VOLUME_PREFIX;
|
import static org.apache.hadoop.ozone.OzoneConsts.OM_S3_VOLUME_PREFIX;
|
||||||
|
@ -162,13 +166,17 @@ public class S3BucketManagerImpl implements S3BucketManager {
|
||||||
boolean newVolumeCreate = true;
|
boolean newVolumeCreate = true;
|
||||||
String ozoneVolumeName = formatOzoneVolumeName(userName);
|
String ozoneVolumeName = formatOzoneVolumeName(userName);
|
||||||
try {
|
try {
|
||||||
OmVolumeArgs args =
|
OmVolumeArgs.Builder builder =
|
||||||
OmVolumeArgs.newBuilder()
|
OmVolumeArgs.newBuilder()
|
||||||
.setAdminName(S3_ADMIN_NAME)
|
.setAdminName(S3_ADMIN_NAME)
|
||||||
.setOwnerName(userName)
|
.setOwnerName(userName)
|
||||||
.setVolume(ozoneVolumeName)
|
.setVolume(ozoneVolumeName)
|
||||||
.setQuotaInBytes(OzoneConsts.MAX_QUOTA_IN_BYTES)
|
.setQuotaInBytes(OzoneConsts.MAX_QUOTA_IN_BYTES);
|
||||||
.build();
|
for (OzoneAcl acl : getDefaultAcls(userName)) {
|
||||||
|
builder.addOzoneAcls(OzoneAcl.toProtobuf(acl));
|
||||||
|
}
|
||||||
|
|
||||||
|
OmVolumeArgs args = builder.build();
|
||||||
if (isRatisEnabled) {
|
if (isRatisEnabled) {
|
||||||
// When ratis is enabled we need to call apply also.
|
// When ratis is enabled we need to call apply also.
|
||||||
volumeManager.applyCreateVolume(args, volumeManager.createVolume(args));
|
volumeManager.applyCreateVolume(args, volumeManager.createVolume(args));
|
||||||
|
@ -189,6 +197,15 @@ public class S3BucketManagerImpl implements S3BucketManager {
|
||||||
return newVolumeCreate;
|
return newVolumeCreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default acls.
|
||||||
|
* */
|
||||||
|
private List<OzoneAcl> getDefaultAcls(String userName) {
|
||||||
|
UserGroupInformation ugi = ProtobufRpcEngine.Server.getRemoteUser();
|
||||||
|
return OzoneAcl.parseAcls("user:" + (ugi == null ? userName :
|
||||||
|
ugi.getUserName()) + ":a,user:" + S3_ADMIN_NAME + ":a");
|
||||||
|
}
|
||||||
|
|
||||||
private void createOzoneBucket(String volumeName, String bucketName)
|
private void createOzoneBucket(String volumeName, String bucketName)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
OmBucketInfo.Builder builder = OmBucketInfo.newBuilder();
|
OmBucketInfo.Builder builder = OmBucketInfo.newBuilder();
|
||||||
|
@ -198,6 +215,7 @@ public class S3BucketManagerImpl implements S3BucketManager {
|
||||||
.setBucketName(bucketName)
|
.setBucketName(bucketName)
|
||||||
.setIsVersionEnabled(Boolean.FALSE)
|
.setIsVersionEnabled(Boolean.FALSE)
|
||||||
.setStorageType(StorageType.DEFAULT)
|
.setStorageType(StorageType.DEFAULT)
|
||||||
|
.setAcls(getDefaultAcls(null))
|
||||||
.build();
|
.build();
|
||||||
bucketManager.createBucket(bucketInfo);
|
bucketManager.createBucket(bucketInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,17 +20,22 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
||||||
|
import org.apache.hadoop.ipc.ProtobufRpcEngine;
|
||||||
import org.apache.hadoop.ozone.OzoneAcl;
|
import org.apache.hadoop.ozone.OzoneAcl;
|
||||||
|
import org.apache.hadoop.ozone.OzoneConfigKeys;
|
||||||
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmDeleteVolumeResponse;
|
import org.apache.hadoop.ozone.om.helpers.OmDeleteVolumeResponse;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
|
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
|
||||||
import org.apache.hadoop.ozone.om.helpers.OmVolumeOwnerChangeResponse;
|
import org.apache.hadoop.ozone.om.helpers.OmVolumeOwnerChangeResponse;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
|
||||||
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.VolumeList;
|
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.VolumeList;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
|
||||||
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
import org.apache.hadoop.ozone.security.acl.OzoneObj;
|
||||||
|
import org.apache.hadoop.ozone.security.acl.RequestContext;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.utils.db.BatchOperation;
|
import org.apache.hadoop.utils.db.BatchOperation;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
@ -53,6 +58,7 @@ public class VolumeManagerImpl implements VolumeManager {
|
||||||
private final OMMetadataManager metadataManager;
|
private final OMMetadataManager metadataManager;
|
||||||
private final int maxUserVolumeCount;
|
private final int maxUserVolumeCount;
|
||||||
private final boolean isRatisEnabled;
|
private final boolean isRatisEnabled;
|
||||||
|
private final boolean aclEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -67,6 +73,8 @@ public class VolumeManagerImpl implements VolumeManager {
|
||||||
isRatisEnabled = conf.getBoolean(
|
isRatisEnabled = conf.getBoolean(
|
||||||
OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY,
|
OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY,
|
||||||
OMConfigKeys.OZONE_OM_RATIS_ENABLE_DEFAULT);
|
OMConfigKeys.OZONE_OM_RATIS_ENABLE_DEFAULT);
|
||||||
|
aclEnabled = conf.getBoolean(OzoneConfigKeys.OZONE_ACL_ENABLED,
|
||||||
|
OzoneConfigKeys.OZONE_ACL_ENABLED_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers to add and delete volume from user list
|
// Helpers to add and delete volume from user list
|
||||||
|
@ -504,8 +512,7 @@ public class VolumeManagerImpl implements VolumeManager {
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
if (!(ex instanceof OMException)) {
|
if (!(ex instanceof OMException)) {
|
||||||
LOG.error("Check volume access failed for volume:{} user:{} rights:{}",
|
LOG.error("Check volume access failed for volume:{} user:{} rights:{}",
|
||||||
volume, userAcl.getName(),
|
volume, userAcl.getName(), userAcl.getRights().toString(), ex);
|
||||||
StringUtils.join(userAcl.getRightsList(), ","), ex);
|
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -521,8 +528,19 @@ public class VolumeManagerImpl implements VolumeManager {
|
||||||
String prefix, String startKey, int maxKeys) throws IOException {
|
String prefix, String startKey, int maxKeys) throws IOException {
|
||||||
metadataManager.getLock().acquireLock(USER_LOCK, userName);
|
metadataManager.getLock().acquireLock(USER_LOCK, userName);
|
||||||
try {
|
try {
|
||||||
return metadataManager.listVolumes(
|
List<OmVolumeArgs> volumes = metadataManager.listVolumes(
|
||||||
userName, prefix, startKey, maxKeys);
|
userName, prefix, startKey, maxKeys);
|
||||||
|
UserGroupInformation userUgi = ProtobufRpcEngine.Server.
|
||||||
|
getRemoteUser();
|
||||||
|
if (userUgi == null || !aclEnabled) {
|
||||||
|
return volumes;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<OmVolumeArgs> filteredVolumes = volumes.stream().
|
||||||
|
filter(v -> v.getAclMap().
|
||||||
|
hasAccess(IAccessAuthorizer.ACLType.LIST, userUgi))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return filteredVolumes;
|
||||||
} finally {
|
} finally {
|
||||||
metadataManager.getLock().releaseLock(USER_LOCK, userName);
|
metadataManager.getLock().releaseLock(USER_LOCK, userName);
|
||||||
}
|
}
|
||||||
|
@ -711,4 +729,44 @@ public class VolumeManagerImpl implements VolumeManager {
|
||||||
metadataManager.getLock().releaseLock(VOLUME_LOCK, volume);
|
metadataManager.getLock().releaseLock(VOLUME_LOCK, volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean checkAccess(OzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException {
|
||||||
|
Objects.requireNonNull(ozObject);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
|
||||||
|
String volume = ozObject.getVolumeName();
|
||||||
|
metadataManager.getLock().acquireLock(VOLUME_LOCK, volume);
|
||||||
|
try {
|
||||||
|
String dbVolumeKey = metadataManager.getVolumeKey(volume);
|
||||||
|
OmVolumeArgs volumeArgs =
|
||||||
|
metadataManager.getVolumeTable().get(dbVolumeKey);
|
||||||
|
if (volumeArgs == null) {
|
||||||
|
LOG.debug("volume:{} does not exist", volume);
|
||||||
|
throw new OMException("Volume " + volume + " is not found",
|
||||||
|
ResultCodes.VOLUME_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
Preconditions.checkState(volume.equals(volumeArgs.getVolume()));
|
||||||
|
boolean hasAccess = volumeArgs.getAclMap().hasAccess(
|
||||||
|
context.getAclRights(), context.getClientUgi());
|
||||||
|
LOG.debug("user:{} has access rights for volume:{} :{} ",
|
||||||
|
context.getClientUgi(), ozObject.getVolumeName(), hasAccess);
|
||||||
|
return hasAccess;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("Check access operation failed for volume:{}", volume, ex);
|
||||||
|
throw new OMException("Check access operation failed for " +
|
||||||
|
"volume:" + volume, ex, ResultCodes.INTERNAL_ERROR);
|
||||||
|
} finally {
|
||||||
|
metadataManager.getLock().releaseLock(VOLUME_LOCK, volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,11 +410,9 @@ public class OzoneManagerRequestHandler implements RequestHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SetAclResponse setAcl(SetAclRequest req) throws IOException {
|
private SetAclResponse setAcl(SetAclRequest req) throws IOException {
|
||||||
List<OzoneAcl> ozoneAcl = new ArrayList<>();
|
|
||||||
req.getAclList().forEach(a ->
|
|
||||||
ozoneAcl.add(OzoneAcl.fromProtobuf(a)));
|
|
||||||
boolean response = impl.setAcl(OzoneObjInfo.fromProtobuf(req.getObj()),
|
boolean response = impl.setAcl(OzoneObjInfo.fromProtobuf(req.getObj()),
|
||||||
ozoneAcl);
|
req.getAclList().stream().map(a -> OzoneAcl.fromProtobuf(a)).
|
||||||
|
collect(Collectors.toList()));
|
||||||
return SetAclResponse.newBuilder().setResponse(response).build();
|
return SetAclResponse.newBuilder().setResponse(response).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with this
|
||||||
|
* work for additional information regarding copyright ownership. The ASF
|
||||||
|
* licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.security.acl;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.ozone.om.BucketManager;
|
||||||
|
import org.apache.hadoop.ozone.om.KeyManager;
|
||||||
|
import org.apache.hadoop.ozone.om.PrefixManager;
|
||||||
|
import org.apache.hadoop.ozone.om.VolumeManager;
|
||||||
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public API for Ozone ACLs. Security providers providing support for Ozone
|
||||||
|
* ACLs should implement this.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.LimitedPrivate({"HDFS", "Yarn", "Ranger", "Hive", "HBase"})
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public class OzoneNativeAuthorizer implements IAccessAuthorizer {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
LoggerFactory.getLogger(OzoneNativeAuthorizer.class);
|
||||||
|
private VolumeManager volumeManager;
|
||||||
|
private BucketManager bucketManager;
|
||||||
|
private KeyManager keyManager;
|
||||||
|
private PrefixManager prefixManager;
|
||||||
|
|
||||||
|
public OzoneNativeAuthorizer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public OzoneNativeAuthorizer(VolumeManager volumeManager,
|
||||||
|
BucketManager bucketManager, KeyManager keyManager,
|
||||||
|
PrefixManager prefixManager) {
|
||||||
|
this.volumeManager = volumeManager;
|
||||||
|
this.bucketManager = bucketManager;
|
||||||
|
this.keyManager = keyManager;
|
||||||
|
this.prefixManager = prefixManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check access for given ozoneObject.
|
||||||
|
*
|
||||||
|
* @param ozObject object for which access needs to be checked.
|
||||||
|
* @param context Context object encapsulating all user related information.
|
||||||
|
* @return true if user has access else false.
|
||||||
|
*/
|
||||||
|
public boolean checkAccess(IOzoneObj ozObject, RequestContext context)
|
||||||
|
throws OMException {
|
||||||
|
Objects.requireNonNull(ozObject);
|
||||||
|
Objects.requireNonNull(context);
|
||||||
|
OzoneObjInfo objInfo;
|
||||||
|
|
||||||
|
if (ozObject instanceof OzoneObjInfo) {
|
||||||
|
objInfo = (OzoneObjInfo) ozObject;
|
||||||
|
} else {
|
||||||
|
throw new OMException("Unexpected input received. OM native acls are " +
|
||||||
|
"configured to work with OzoneObjInfo type only.", INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (objInfo.getResourceType()) {
|
||||||
|
case VOLUME:
|
||||||
|
LOG.trace("Checking access for volume:" + objInfo);
|
||||||
|
return volumeManager.checkAccess(objInfo, context);
|
||||||
|
case BUCKET:
|
||||||
|
LOG.trace("Checking access for bucket:" + objInfo);
|
||||||
|
return (bucketManager.checkAccess(objInfo, context)
|
||||||
|
&& volumeManager.checkAccess(objInfo, context));
|
||||||
|
case KEY:
|
||||||
|
LOG.trace("Checking access for Key:" + objInfo);
|
||||||
|
return (keyManager.checkAccess(objInfo, context)
|
||||||
|
&& prefixManager.checkAccess(objInfo, context)
|
||||||
|
&& bucketManager.checkAccess(objInfo, context)
|
||||||
|
&& volumeManager.checkAccess(objInfo, context));
|
||||||
|
case PREFIX:
|
||||||
|
LOG.trace("Checking access for Prefix:" + objInfo);
|
||||||
|
return (prefixManager.checkAccess(objInfo, context)
|
||||||
|
&& bucketManager.checkAccess(objInfo, context)
|
||||||
|
&& volumeManager.checkAccess(objInfo, context));
|
||||||
|
default:
|
||||||
|
throw new OMException("Unexpected object type:" +
|
||||||
|
objInfo.getResourceType(), INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVolumeManager(VolumeManager volumeManager) {
|
||||||
|
this.volumeManager = volumeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBucketManager(BucketManager bucketManager) {
|
||||||
|
this.bucketManager = bucketManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyManager(KeyManager keyManager) {
|
||||||
|
this.keyManager = keyManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefixManager(PrefixManager prefixManager) {
|
||||||
|
this.prefixManager = prefixManager;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.security.acl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OM native acl implementation.
|
||||||
|
*/
|
|
@ -77,7 +77,7 @@ public class ListVolumeHandler extends Handler {
|
||||||
OzoneClient client = address.createClient(createOzoneConfiguration());
|
OzoneClient client = address.createClient(createOzoneConfiguration());
|
||||||
|
|
||||||
if (userName == null) {
|
if (userName == null) {
|
||||||
userName = UserGroupInformation.getCurrentUser().getShortUserName();
|
userName = UserGroupInformation.getCurrentUser().getUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxVolumes < 1) {
|
if (maxVolumes < 1) {
|
||||||
|
|
|
@ -43,6 +43,10 @@ import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException;
|
import org.apache.hadoop.fs.PathIsNotEmptyDirectoryException;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
|
|
||||||
|
import org.apache.hadoop.ozone.om.exceptions.OMException;
|
||||||
|
import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
|
||||||
|
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
import org.apache.hadoop.util.Progressable;
|
import org.apache.hadoop.util.Progressable;
|
||||||
|
@ -589,7 +593,7 @@ public class BasicOzoneFileSystem extends FileSystem {
|
||||||
throw new FileAlreadyExistsException(String.format(
|
throw new FileAlreadyExistsException(String.format(
|
||||||
"Can't make directory for path '%s', it is a file.", fPart));
|
"Can't make directory for path '%s', it is a file.", fPart));
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException fnfe) {
|
} catch (FileNotFoundException | OMException fnfe) {
|
||||||
LOG.trace("creating directory for fpart:{}", fPart);
|
LOG.trace("creating directory for fpart:{}", fPart);
|
||||||
String key = pathToKey(fPart);
|
String key = pathToKey(fPart);
|
||||||
String dirKey = addTrailingSlashIfNeeded(key);
|
String dirKey = addTrailingSlashIfNeeded(key);
|
||||||
|
@ -626,9 +630,16 @@ public class BasicOzoneFileSystem extends FileSystem {
|
||||||
LOG.trace("getFileStatus() path:{}", f);
|
LOG.trace("getFileStatus() path:{}", f);
|
||||||
Path qualifiedPath = f.makeQualified(uri, workingDir);
|
Path qualifiedPath = f.makeQualified(uri, workingDir);
|
||||||
String key = pathToKey(qualifiedPath);
|
String key = pathToKey(qualifiedPath);
|
||||||
FileStatus status = convertFileStatus(
|
FileStatus fileStatus = null;
|
||||||
adapter.getFileStatus(key, uri, qualifiedPath, getUsername()));
|
try {
|
||||||
return status;
|
fileStatus = adapter.getFileStatus(key)
|
||||||
|
.makeQualified(uri, qualifiedPath, getUsername(), getUsername());
|
||||||
|
} catch (OMException ex) {
|
||||||
|
if (ex.getResult().equals(OMException.ResultCodes.KEY_NOT_FOUND)) {
|
||||||
|
throw new FileNotFoundException("File not found. path:" + f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -378,7 +378,7 @@ public class SQLCLI extends Configured implements Tool {
|
||||||
for (OzoneAclInfo aclInfo : volumeInfo.getVolumeAclsList()) {
|
for (OzoneAclInfo aclInfo : volumeInfo.getVolumeAclsList()) {
|
||||||
String insertAclInfo =
|
String insertAclInfo =
|
||||||
String.format(INSERT_ACL_INFO, adminName, ownerName, volumeName,
|
String.format(INSERT_ACL_INFO, adminName, ownerName, volumeName,
|
||||||
aclInfo.getType(), aclInfo.getName(), aclInfo.getRightsList());
|
aclInfo.getType(), aclInfo.getName(), aclInfo.getRights());
|
||||||
executeSQL(conn, insertAclInfo);
|
executeSQL(conn, insertAclInfo);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue