HDFS-8654. OzoneHandler : Add ACL support. (Contributed by Anu Engineer)

This commit is contained in:
Arpit Agarwal 2015-07-07 08:59:28 -07:00 committed by Owen O'Malley
parent b1fa06aacb
commit 835f872a0a
4 changed files with 352 additions and 0 deletions

View File

@ -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)

View File

@ -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");
}
}
}
}

View File

@ -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
} }

View File

@ -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);
}
}