blob: c4b80c7e17304d77079bea015ddaf31c4706f0b9 [file] [log] [blame]
/*
* 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.om.multitenant;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_TENANT_RANGER_POLICY_LABEL;
import static org.apache.hadoop.ozone.om.multitenant.AccessPolicy.AccessPolicyType.RANGER_POLICY;
/**
* This is used for Ozone tenant access policy control.
*/
public class RangerAccessPolicy implements AccessPolicy {
// For now RangerAccessPolicy supports only one object per policy
private OzoneObj accessObject;
private final Map<String, List<AccessPolicyElem>> policyMap;
private final HashSet<String> roleList;
private String policyID;
private String policyJsonString;
private String policyName;
private long lastPolicyUpdateTimeEpochMillis;
public RangerAccessPolicy(String name) {
policyMap = new ConcurrentHashMap<>();
policyName = name;
roleList = new HashSet<>();
}
public void setPolicyID(String id) {
policyID = id;
}
public String getPolicyID() {
return policyID;
}
public String getPolicyName() {
return policyName;
}
public HashSet<String> getRoleList() {
return roleList;
}
@Override
public void setPolicyLastUpdateTime(long mtime) {
lastPolicyUpdateTimeEpochMillis = mtime;
}
@Override
public long getPolicyLastUpdateTime() {
return lastPolicyUpdateTimeEpochMillis;
}
@Override
public String serializePolicyToJsonString() throws IOException {
updatePolicyJsonString();
return policyJsonString;
}
@Override
public String deserializePolicyFromJsonString(JsonObject jsonObject) {
setPolicyID(jsonObject.get("id").getAsString());
try {
JsonArray policyItems = jsonObject
.getAsJsonArray("policyItems");
for (int j = 0; j < policyItems.size(); ++j) {
JsonObject policy = policyItems.get(j).getAsJsonObject();
JsonArray roles = policy.getAsJsonArray("roles");
for (int k = 0; k < roles.size(); ++k) {
if (!roleList.contains(roles.get(k).getAsString())) {
// We only get the role name here. We need to query and populate it.
roleList.add(roles.get(k).getAsString());
}
}
}
} catch (Exception e) {
// Ignore Exception here.
}
// TODO : retrieve other policy fields as well.
try {
setPolicyLastUpdateTime(jsonObject.get("updateTime").getAsLong());
} catch (Exception e) {
// lets ignore the exception in case the field is not set.
}
return null;
}
@Override
public AccessPolicyType getAccessPolicyType() {
return RANGER_POLICY;
}
@Override
public void addAccessPolicyElem(OzoneObj object,
Principal principal,
ACLType acl, AccessGrantType grant)
throws IOException {
if (accessObject == null) {
accessObject = object;
} else if (!object.toString().equals(accessObject.toString())) {
throw new IOException(
"RangerAccessPolicy supports only one object per" + " policy");
}
AccessPolicyElem elem = new AccessPolicyElem(object, principal, acl, grant);
if (!policyMap.containsKey(principal.getName())) {
List<AccessPolicyElem> elemList = new ArrayList<>();
elemList.add(elem);
policyMap.put(principal.getName(), elemList);
return;
}
List<AccessPolicyElem> elemList = policyMap.get(principal.getName());
for (AccessPolicyElem e : elemList) {
if (e.getAclType() == acl) {
throw new IOException(
"RangerAccessPolicy: Principal " + principal.getName()
+ " already exists with access " + acl);
}
}
elemList.add(elem);
}
@Override
public List<AccessPolicyElem> getAccessPolicyElem() {
List<AccessPolicyElem> list = new ArrayList<>();
for (Map.Entry<String, List<AccessPolicyElem>> entry : policyMap
.entrySet()) {
list.addAll(entry.getValue());
}
return list;
}
@Override
public void removeAccessPolicyElem(OzoneObj object,
Principal principal, ACLType acl,
AccessGrantType grant)
throws IOException {
if (accessObject == null) {
throw new IOException("removeAccessPolicyElem: Invalid Arguments.");
} else if (!object.toString().equals(accessObject.toString())) {
throw new IOException(
"removeAccessPolicyElem: Object not found." + object.toString());
}
if (!policyMap.containsKey(principal.getName())) {
throw new IOException(
"removeAccessPolicyElem: Principal not found." + object.toString());
}
List<AccessPolicyElem> elemList = policyMap.get(principal.getName());
for (AccessPolicyElem e : elemList) {
if (e.getAclType() == acl) {
elemList.remove(e);
}
}
if (elemList.isEmpty()) {
policyMap.remove(principal.toString());
}
throw new IOException(
"removeAccessPolicyElem: aclType not found." + object.toString());
}
private String createRangerResourceItems() {
StringBuilder resourceItems = new StringBuilder();
resourceItems.append("\"resources\":{" +
"\"volume\":{" +
"\"values\":[\"");
resourceItems.append(accessObject.getVolumeName());
resourceItems.append("\"]," +
"\"isRecursive\":false," +
"\"isExcludes\":false" +
"}");
if ((accessObject.getResourceType() == OzoneObj.ResourceType.BUCKET) ||
(accessObject.getResourceType() == OzoneObj.ResourceType.KEY)) {
resourceItems.append(
",\"bucket\":{" +
"\"values\":[\"");
resourceItems.append(accessObject.getBucketName());
resourceItems.append("\"]," +
"\"isRecursive\":false," +
"\"isExcludes\":false" +
"}");
}
if (accessObject.getResourceType() == OzoneObj.ResourceType.KEY) {
resourceItems.append(",\"key\":{" +
"\"values\":[\"");
resourceItems.append(accessObject.getKeyName());
resourceItems.append("\"]," +
"\"isRecursive\":true," +
"\"isExcludes\":false" +
"}");
}
resourceItems.append("},");
return resourceItems.toString();
}
private String createRangerPolicyItems() throws IOException {
StringBuilder policyItems = new StringBuilder();
policyItems.append("\"policyItems\":[");
int mapRemainingSize = policyMap.size();
for (Map.Entry<String, List<AccessPolicyElem>> mapElem : policyMap
.entrySet()) {
mapRemainingSize--;
List<AccessPolicyElem> list = mapElem.getValue();
if (list.isEmpty()) {
continue;
}
policyItems.append("{");
if (list.get(0).getPrincipal() instanceof OzoneTenantRolePrincipal) {
policyItems.append("\"roles\":[\"" + mapElem.getKey() + "\"],");
} else {
policyItems.append("\"users\":[\"" + mapElem.getKey() + "\"],");
}
policyItems.append("\"accesses\":[");
Iterator<AccessPolicyElem> iter = list.iterator();
while (iter.hasNext()) {
AccessPolicyElem elem = iter.next();
policyItems.append("{");
policyItems.append("\"type\":\"");
policyItems.append(getRangerAclString(elem.getAclType()));
policyItems.append("\",");
if (elem.getAccessGrantType() == AccessGrantType.ALLOW) {
policyItems.append("\"isAllowed\":true");
} else {
policyItems.append("\"isDenied\":true");
}
policyItems.append("}");
if (iter.hasNext()) {
policyItems.append(",");
}
}
policyItems.append("]");
policyItems.append("}");
if (mapRemainingSize > 0) {
policyItems.append(",");
}
}
policyItems.append("],");
return policyItems.toString();
}
private String getRangerAclString(ACLType aclType) throws IOException {
switch (aclType) {
case ALL:
return "All";
case LIST:
return "List";
case READ:
return "Read";
case WRITE:
return "Write";
case CREATE:
return "Create";
case DELETE:
return "Delete";
case READ_ACL:
return "Read_ACL";
case WRITE_ACL:
return "Write_ACL";
case NONE:
return "";
default:
throw new IOException("Unknown ACLType");
}
}
private void updatePolicyJsonString() throws IOException {
policyJsonString =
"{\"policyType\":\"0\"," + "\"name\":\"" + policyName + "\","
+ "\"isEnabled\":true," + "\"policyPriority\":0,"
+ "\"description\":\"Policy created by Ozone for Multi-Tenancy\","
+ "\"policyLabels\":[\"" + OZONE_TENANT_RANGER_POLICY_LABEL + "\"],"
+ "\"description\":\"\","
+ "\"isAuditEnabled\":true," + createRangerResourceItems()
+ "\"isDenyAllElse\":false," + createRangerPolicyItems()
+ "\"allowExceptions\":[]," + "\"denyPolicyItems\":[],"
+ "\"denyExceptions\":[]," + "\"service\":\"cm_ozone\"" + "}";
}
@Override
public String toString() {
return "RangerAccessPolicy{" + "accessObject=" + accessObject
+ ", policyMap=" + policyMap + ", roleList=" + roleList + ", policyID='"
+ policyID + '\'' + ", policyJsonString='" + policyJsonString + '\''
+ ", policyName='" + policyName + '\''
+ ", lastPolicyUpdateTimeEpochMillis=" + lastPolicyUpdateTimeEpochMillis
+ '}';
}
}