HDFS-8654. OzoneHandler : Add ACL support. (Contributed by Anu Engineer)
This commit is contained in:
parent
b1fa06aacb
commit
835f872a0a
|
@ -20,3 +20,4 @@
|
||||||
HDFS-8644. OzoneHandler : Add volume handler. (Anu Engineer via
|
HDFS-8644. OzoneHandler : Add volume handler. (Anu Engineer via
|
||||||
Arpit Agarwal)
|
Arpit Agarwal)
|
||||||
|
|
||||||
|
HDFS-8654. OzoneHandler : Add ACL support. (Anu Engineer via Arpit Agarwal)
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
* 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.web.request;
|
||||||
|
|
||||||
|
import org.apache.hadoop.ozone.web.utils.OzoneConsts;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OzoneACL classes define bucket ACLs used in OZONE.
|
||||||
|
*
|
||||||
|
* ACLs in Ozone follow this pattern.
|
||||||
|
* • user:name:rw
|
||||||
|
* • group:name:rw
|
||||||
|
* • world::rw
|
||||||
|
*/
|
||||||
|
public class OzoneAcl {
|
||||||
|
private OzoneACLType type;
|
||||||
|
private String name;
|
||||||
|
private OzoneACLRights rights;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for OzoneAcl.
|
||||||
|
*
|
||||||
|
* @param type - Type
|
||||||
|
* @param name - Name of user
|
||||||
|
* @param rights - Rights
|
||||||
|
*/
|
||||||
|
public OzoneAcl(OzoneACLType type, String name, OzoneACLRights rights) {
|
||||||
|
this.name = name;
|
||||||
|
this.rights = rights;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an ACL string and returns the ACL object.
|
||||||
|
*
|
||||||
|
* @param acl - Acl String , Ex. user:anu:rw
|
||||||
|
*
|
||||||
|
* @return - Ozone ACLs
|
||||||
|
*/
|
||||||
|
public static OzoneAcl parseAcl(String acl) throws IllegalArgumentException {
|
||||||
|
if ((acl == null) || acl.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ACLs cannot be null or empty");
|
||||||
|
}
|
||||||
|
String[] parts = acl.trim().split(":");
|
||||||
|
if (parts.length < 3) {
|
||||||
|
throw new IllegalArgumentException("ACLs are not in expected format");
|
||||||
|
}
|
||||||
|
|
||||||
|
OzoneACLType aclType = OzoneACLType.valueOf(parts[0].toUpperCase());
|
||||||
|
OzoneACLRights rights = OzoneACLRights.getACLRight(parts[2].toLowerCase());
|
||||||
|
|
||||||
|
if (((aclType == OzoneACLType.USER) || (aclType == OzoneACLType.GROUP))
|
||||||
|
&& (parts[1].length() == 0)) {
|
||||||
|
throw new IllegalArgumentException("User or group name is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((aclType == OzoneACLType.WORLD) && (parts[1].length() != 0)) {
|
||||||
|
throw new IllegalArgumentException("Unexpected name part in world type");
|
||||||
|
}
|
||||||
|
// TODO : Support sanitation of these user names by calling into
|
||||||
|
// userAuth Interface.
|
||||||
|
return new OzoneAcl(aclType, parts[1], rights);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash code value for the object. This method is
|
||||||
|
* supported for the benefit of hash tables.
|
||||||
|
*
|
||||||
|
* @return a hash code value for this object.
|
||||||
|
*
|
||||||
|
* @see Object#equals(Object)
|
||||||
|
* @see System#identityHashCode
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.getName(), this.getRights().toString(),
|
||||||
|
this.getType().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns name.
|
||||||
|
*
|
||||||
|
* @return name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Rights.
|
||||||
|
*
|
||||||
|
* @return - Rights
|
||||||
|
*/
|
||||||
|
public OzoneACLRights getRights() {
|
||||||
|
return rights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Type.
|
||||||
|
*
|
||||||
|
* @return type
|
||||||
|
*/
|
||||||
|
public OzoneACLType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether some other object is "equal to" this one.
|
||||||
|
*
|
||||||
|
* @param obj the reference object with which to compare.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this object is the same as the obj
|
||||||
|
* argument; {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OzoneAcl otherAcl = (OzoneAcl) obj;
|
||||||
|
return otherAcl.getName().equals(this.getName()) &&
|
||||||
|
otherAcl.getRights() == this.getRights() &&
|
||||||
|
otherAcl.getType() == this.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL types.
|
||||||
|
*/
|
||||||
|
public enum OzoneACLType {
|
||||||
|
USER(OzoneConsts.OZONE_ACL_USER_TYPE),
|
||||||
|
GROUP(OzoneConsts.OZONE_ACL_GROUP_TYPE),
|
||||||
|
WORLD(OzoneConsts.OZONE_ACL_WORLD_TYPE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String value for this Enum.
|
||||||
|
*/
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init OzoneACLtypes enum.
|
||||||
|
*
|
||||||
|
* @param val String type for this enum.
|
||||||
|
*/
|
||||||
|
OzoneACLType(String val) {
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL rights.
|
||||||
|
*/
|
||||||
|
public enum OzoneACLRights {
|
||||||
|
READ, WRITE, READ_WRITE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ACL rights based on passed in String.
|
||||||
|
*
|
||||||
|
* @param type ACL right string
|
||||||
|
*
|
||||||
|
* @return OzoneACLRights
|
||||||
|
*/
|
||||||
|
public static OzoneACLRights getACLRight(String type) {
|
||||||
|
if (type == null || type.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ACL right cannot be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case OzoneConsts.OZONE_ACL_READ:
|
||||||
|
return OzoneACLRights.READ;
|
||||||
|
case OzoneConsts.OZONE_ACL_WRITE:
|
||||||
|
return OzoneACLRights.WRITE;
|
||||||
|
case OzoneConsts.OZONE_ACL_READ_WRITE:
|
||||||
|
case OzoneConsts.OZONE_ACL_WRITE_READ:
|
||||||
|
return OzoneACLRights.READ_WRITE;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("ACL right is not recognized");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,6 +34,15 @@ public final class OzoneConsts {
|
||||||
public static final int OZONE_MIN_BUCKET_NAME_LENGTH = 3;
|
public static final int OZONE_MIN_BUCKET_NAME_LENGTH = 3;
|
||||||
public static final int OZONE_MAX_BUCKET_NAME_LENGTH = 63;
|
public static final int OZONE_MAX_BUCKET_NAME_LENGTH = 63;
|
||||||
|
|
||||||
|
public static final String OZONE_ACL_USER_TYPE = "user";
|
||||||
|
public static final String OZONE_ACL_GROUP_TYPE = "group";
|
||||||
|
public static final String OZONE_ACL_WORLD_TYPE = "world";
|
||||||
|
|
||||||
|
public static final String OZONE_ACL_READ = "r";
|
||||||
|
public static final String OZONE_ACL_WRITE = "w";
|
||||||
|
public static final String OZONE_ACL_READ_WRITE = "rw";
|
||||||
|
public static final String OZONE_ACL_WRITE_READ = "wr";
|
||||||
|
|
||||||
private OzoneConsts() {
|
private OzoneConsts() {
|
||||||
// Never Constructed
|
// Never Constructed
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/**
|
||||||
|
* 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.web;
|
||||||
|
|
||||||
|
import org.apache.hadoop.ozone.web.request.OzoneAcl;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class TestOzoneAcls {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void TestACLParse() {
|
||||||
|
HashMap<String, Boolean> testMatrix;
|
||||||
|
testMatrix = new HashMap<>();
|
||||||
|
|
||||||
|
testMatrix.put("user:bilbo:r", Boolean.TRUE);
|
||||||
|
testMatrix.put("user:bilbo:w", Boolean.TRUE);
|
||||||
|
testMatrix.put("user:bilbo:rw", Boolean.TRUE);
|
||||||
|
testMatrix.put("user:bilbo:wr", Boolean.TRUE);
|
||||||
|
testMatrix.put(" user:bilbo:wr ", Boolean.TRUE);
|
||||||
|
|
||||||
|
|
||||||
|
// ACLs makes no judgement on the quality of
|
||||||
|
// user names. it is for the userAuth interface
|
||||||
|
// to determine if a user name is really a name
|
||||||
|
testMatrix.put(" user:*:rw", Boolean.TRUE);
|
||||||
|
testMatrix.put(" user:~!:rw", Boolean.TRUE);
|
||||||
|
|
||||||
|
|
||||||
|
testMatrix.put("", Boolean.FALSE);
|
||||||
|
testMatrix.put(null, Boolean.FALSE);
|
||||||
|
testMatrix.put(" user:bilbo:", Boolean.FALSE);
|
||||||
|
testMatrix.put(" user:bilbo:rx", Boolean.FALSE);
|
||||||
|
testMatrix.put(" user:bilbo:mk", Boolean.FALSE);
|
||||||
|
testMatrix.put(" user::rw", Boolean.FALSE);
|
||||||
|
testMatrix.put("user11:bilbo:rw", Boolean.FALSE);
|
||||||
|
testMatrix.put(" user:::rw", Boolean.FALSE);
|
||||||
|
|
||||||
|
testMatrix.put(" group:hobbit:r", Boolean.TRUE);
|
||||||
|
testMatrix.put(" group:hobbit:w", Boolean.TRUE);
|
||||||
|
testMatrix.put(" group:hobbit:rw", Boolean.TRUE);
|
||||||
|
testMatrix.put(" group:hobbit:wr", Boolean.TRUE);
|
||||||
|
testMatrix.put(" group:*:rw", Boolean.TRUE);
|
||||||
|
testMatrix.put(" group:~!:rw", Boolean.TRUE);
|
||||||
|
|
||||||
|
testMatrix.put(" group:hobbit:", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group:hobbit:rx", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group:hobbit:mk", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group::", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group::rw", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group22:hobbit:", Boolean.FALSE);
|
||||||
|
testMatrix.put(" group:::rw", Boolean.FALSE);
|
||||||
|
|
||||||
|
testMatrix.put("JUNK group:hobbit:r", Boolean.FALSE);
|
||||||
|
testMatrix.put("JUNK group:hobbit:w", Boolean.FALSE);
|
||||||
|
testMatrix.put("JUNK group:hobbit:rw", Boolean.FALSE);
|
||||||
|
testMatrix.put("JUNK group:hobbit:wr", Boolean.FALSE);
|
||||||
|
testMatrix.put("JUNK group:*:rw", Boolean.FALSE);
|
||||||
|
testMatrix.put("JUNK group:~!:rw", Boolean.FALSE);
|
||||||
|
|
||||||
|
testMatrix.put(" world::r", Boolean.TRUE);
|
||||||
|
testMatrix.put(" world::w", Boolean.TRUE);
|
||||||
|
testMatrix.put(" world::rw", Boolean.TRUE);
|
||||||
|
testMatrix.put(" world::wr", Boolean.TRUE);
|
||||||
|
|
||||||
|
testMatrix.put(" world:bilbo:w", Boolean.FALSE);
|
||||||
|
testMatrix.put(" world:bilbo:rw", Boolean.FALSE);
|
||||||
|
|
||||||
|
Set<String> keys = testMatrix.keySet();
|
||||||
|
for (String key : keys) {
|
||||||
|
if (testMatrix.get(key)) {
|
||||||
|
OzoneAcl.parseAcl(key);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
OzoneAcl.parseAcl(key);
|
||||||
|
// should never get here since parseAcl will throw
|
||||||
|
fail("An exception was expected but did not happen.");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void TestACLValues() {
|
||||||
|
OzoneAcl acl = OzoneAcl.parseAcl("user:bilbo:rw");
|
||||||
|
assertEquals(acl.getName(), "bilbo");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.READ_WRITE);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.USER);
|
||||||
|
|
||||||
|
acl = OzoneAcl.parseAcl("user:bilbo:wr");
|
||||||
|
assertEquals(acl.getName(), "bilbo");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.READ_WRITE);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.USER);
|
||||||
|
|
||||||
|
acl = OzoneAcl.parseAcl("user:bilbo:r");
|
||||||
|
assertEquals(acl.getName(), "bilbo");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.READ);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.USER);
|
||||||
|
|
||||||
|
acl = OzoneAcl.parseAcl("user:bilbo:w");
|
||||||
|
assertEquals(acl.getName(), "bilbo");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.WRITE);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.USER);
|
||||||
|
|
||||||
|
acl = OzoneAcl.parseAcl("group:hobbit:wr");
|
||||||
|
assertEquals(acl.getName(), "hobbit");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.READ_WRITE);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.GROUP);
|
||||||
|
|
||||||
|
acl = OzoneAcl.parseAcl("world::wr");
|
||||||
|
assertEquals(acl.getName(), "");
|
||||||
|
assertEquals(acl.getRights(), OzoneAcl.OzoneACLRights.READ_WRITE);
|
||||||
|
assertEquals(acl.getType(), OzoneAcl.OzoneACLType.WORLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue