diff --git a/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java b/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java index af15f0818a..4c6470660e 100644 --- a/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java +++ b/authz-api/src/main/java/org/apache/ranger/authz/model/RangerAuthzResult.java @@ -106,12 +106,12 @@ public String toString() { @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public static class PermissionResult { - private String permission; - private AccessResult access; - private DataMaskResult dataMask; - private RowFilterResult rowFilter; - private Map subResources; - private Map additionalInfo; + private String permission; + private AccessResult access; + private DataMaskResult dataMask; + private RowFilterResult rowFilter; + private Map additionalInfo; + private Map subResources; public PermissionResult() { } @@ -120,14 +120,20 @@ public PermissionResult(String permission) { this(permission, null, null); } - public PermissionResult(String permission, AccessResult access) { - this(permission, access, null); + public PermissionResult(String permission, ResultInfo result) { + this(permission, result, null); } - public PermissionResult(String permission, AccessResult access, Map additionalInfo) { - this.permission = permission; - this.access = access; - this.additionalInfo = additionalInfo; + public PermissionResult(String permission, ResultInfo result, Map subResources) { + this.permission = permission; + this.subResources = subResources; + + if (result != null) { + this.access = result.getAccess(); + this.dataMask = result.getDataMask(); + this.rowFilter = result.getRowFilter(); + this.additionalInfo = result.getAdditionalInfo(); + } } // Getters and Setters @@ -163,21 +169,29 @@ public void setRowFilter(RowFilterResult rowFilter) { this.rowFilter = rowFilter; } - public Map getSubResources() { + public Map getAdditionalInfo() { + return additionalInfo; + } + + public void setAdditionalInfo(Map additionalInfo) { + this.additionalInfo = additionalInfo; + } + + public Map getSubResources() { return subResources; } - public void setSubResources(Map subResources) { + public void setSubResources(Map subResources) { this.subResources = subResources; } - public PermissionResult getdSubResourceResult(String resourceName) { - Map subResources = getSubResources(); + public ResultInfo getSubResourceResult(String resourceName) { + Map subResources = getSubResources(); return subResources != null ? subResources.get(resourceName) : null; } - public void addSubResourceResult(String resourceName, PermissionResult result) { + public void addSubResourceResult(String resourceName, ResultInfo result) { if (subResources == null) { subResources = new HashMap<>(); } @@ -185,6 +199,85 @@ public void addSubResourceResult(String resourceName, PermissionResult result) { subResources.put(resourceName, result); } + @Override + public int hashCode() { + return Objects.hash(permission, access, dataMask, rowFilter, additionalInfo, subResources); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } else if (o == null || getClass() != o.getClass()) { + return false; + } + + PermissionResult that = (PermissionResult) o; + + return Objects.equals(permission, that.permission) && + Objects.equals(access, that.access) && + Objects.equals(dataMask, that.dataMask) && + Objects.equals(rowFilter, that.rowFilter) && + Objects.equals(additionalInfo, that.additionalInfo) && + Objects.equals(subResources, that.subResources); + } + + @Override + public String toString() { + return "PermissionResult{" + + "permission='" + permission + '\'' + + ", access=" + access + + ", dataMask=" + dataMask + + ", rowFilter=" + rowFilter + + ", additionalInfo=" + additionalInfo + + ", subResources=" + subResources + + '}'; + } + } + + @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ResultInfo { + private AccessResult access; + private DataMaskResult dataMask; + private RowFilterResult rowFilter; + private Map additionalInfo; + + public ResultInfo() { + } + + public ResultInfo(AccessResult access, DataMaskResult dataMask, RowFilterResult rowFilter, Map additionalInfo) { + this.access = access; + this.dataMask = dataMask; + this.rowFilter = rowFilter; + this.additionalInfo = additionalInfo; + } + + public AccessResult getAccess() { + return access; + } + + public void setAccess(AccessResult access) { + this.access = access; + } + + public DataMaskResult getDataMask() { + return dataMask; + } + + public void setDataMask(DataMaskResult dataMask) { + this.dataMask = dataMask; + } + + public RowFilterResult getRowFilter() { + return rowFilter; + } + + public void setRowFilter(RowFilterResult rowFilter) { + this.rowFilter = rowFilter; + } + public Map getAdditionalInfo() { return additionalInfo; } @@ -195,7 +288,7 @@ public void setAdditionalInfo(Map additionalInfo) { @Override public int hashCode() { - return Objects.hash(permission, access, dataMask, rowFilter, subResources, additionalInfo); + return Objects.hash(access, dataMask, rowFilter, additionalInfo); } @Override @@ -206,24 +299,20 @@ public boolean equals(Object o) { return false; } - PermissionResult that = (PermissionResult) o; + ResultInfo that = (ResultInfo) o; - return Objects.equals(permission, that.permission) && - Objects.equals(access, that.access) && + return Objects.equals(access, that.access) && Objects.equals(dataMask, that.dataMask) && Objects.equals(rowFilter, that.rowFilter) && - Objects.equals(subResources, that.subResources) && Objects.equals(additionalInfo, that.additionalInfo); } @Override public String toString() { - return "PermissionResult{" + - "permission='" + permission + '\'' + - ", access=" + access + + return "ResultInfo{" + + "access=" + access + ", dataMask=" + dataMask + ", rowFilter=" + rowFilter + - ", subResources=" + subResources + ", additionalInfo=" + additionalInfo + '}'; } diff --git a/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java b/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java index cf789f482c..620fdaed6f 100644 --- a/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java +++ b/authz-api/src/main/java/org/apache/ranger/authz/util/RangerResourceNameParser.java @@ -36,8 +36,9 @@ public class RangerResourceNameParser { private static final Logger LOG = LoggerFactory.getLogger(RangerResourceNameParser.class); - public static final String[] EMPTY_ARRAY = new String[0]; - public static final char RRN_RESOURCE_TYPE_SEP = ':'; + public static final String[] EMPTY_ARRAY = new String[0]; + public static final char RRN_RESOURCE_TYPE_SEP = ':'; + public static final char DEFAULT_RRN_RESOURCE_SEP = '/'; private static final char ESCAPE_CHAR = '\\'; private static final String ESCAPE_STRING = "\\\\"; @@ -49,8 +50,25 @@ public class RangerResourceNameParser { private final String template; // examples: database/table/column, bucket/volume/path private final String[] resources; // examples: [database, table, column], [bucket, volume, path] + public RangerResourceNameParser(String[] resourcePath) throws RangerAuthzException { + this(resourcePath, DEFAULT_RRN_RESOURCE_SEP); + } + public RangerResourceNameParser(String[] resourcePath, char separatorChar) throws RangerAuthzException { - this(StringUtils.join(resourcePath, separatorChar), separatorChar); + if (resourcePath == null || resourcePath.length == 0) { + throw new RangerAuthzException(INVALID_RESOURCE_TEMPLATE_EMPTY_VALUE); + } + + this.separatorChar = separatorChar; + this.separatorString = String.valueOf(separatorChar); + this.escapedSeparator = ESCAPE_STRING + separatorString; + this.separatorPattern = Pattern.compile(separatorString); + this.template = StringUtils.join(resourcePath, separatorChar); + this.resources = resourcePath; + } + + public RangerResourceNameParser(String template) throws RangerAuthzException { + this(template, DEFAULT_RRN_RESOURCE_SEP); } public RangerResourceNameParser(String template, char separatorChar) throws RangerAuthzException { diff --git a/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java b/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java index 06e0fe564b..ceeaaf63df 100644 --- a/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java +++ b/authz-api/src/test/java/org/apache/ranger/authz/util/TestRangerResourceNameParser.java @@ -36,8 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertThrowsExactly; public class TestRangerResourceNameParser { - private static final char RRN_RESOURCE_SEP_CHAR = '/'; - @Test public void testValidTemplates() throws Exception { Object[][] testData = { @@ -62,7 +60,7 @@ public void testValidTemplates() throws Exception { String template = (String) test[0]; String resourceType = (String) test[1]; int resourceCount = (Integer) test[2]; - RangerResourceNameParser resourceTemplate = new RangerResourceNameParser(template, RRN_RESOURCE_SEP_CHAR); + RangerResourceNameParser resourceTemplate = new RangerResourceNameParser(template); assertEquals(resourceType, resourceTemplate.getResourceType(), template); assertEquals(resourceCount, resourceTemplate.count(), template); @@ -83,7 +81,7 @@ public void testInvalidTemplates() { }; for (String template : templates) { - RangerAuthzException excp = assertThrowsExactly(RangerAuthzException.class, () -> new RangerResourceNameParser(template, RRN_RESOURCE_SEP_CHAR), template); + RangerAuthzException excp = assertThrowsExactly(RangerAuthzException.class, () -> new RangerResourceNameParser(template), template); assertEquals(INVALID_RESOURCE_TEMPLATE_EMPTY_VALUE.getCode(), excp.getErrorCode().getCode(), template); } @@ -303,13 +301,13 @@ public void testResourceNameFromArrayS3() throws Exception { private static Map getHiveTemplates() throws Exception { Map ret = new HashMap<>(); - ret.put("database", new RangerResourceNameParser("database", RRN_RESOURCE_SEP_CHAR)); - ret.put("table", new RangerResourceNameParser("database/table", RRN_RESOURCE_SEP_CHAR)); - ret.put("column", new RangerResourceNameParser("database/table/column", RRN_RESOURCE_SEP_CHAR)); - ret.put("udf", new RangerResourceNameParser("database/udf", RRN_RESOURCE_SEP_CHAR)); - ret.put("url", new RangerResourceNameParser("url", RRN_RESOURCE_SEP_CHAR)); - ret.put("hiveservice", new RangerResourceNameParser("hiveservice", RRN_RESOURCE_SEP_CHAR)); - ret.put("global", new RangerResourceNameParser("global", RRN_RESOURCE_SEP_CHAR)); + ret.put("database", new RangerResourceNameParser("database")); + ret.put("table", new RangerResourceNameParser("database/table")); + ret.put("column", new RangerResourceNameParser("database/table/column")); + ret.put("udf", new RangerResourceNameParser("database/udf")); + ret.put("url", new RangerResourceNameParser("url")); + ret.put("hiveservice", new RangerResourceNameParser("hiveservice")); + ret.put("global", new RangerResourceNameParser("global")); return ret; } @@ -317,8 +315,8 @@ private static Map getHiveTemplates() throws E private static Map getS3Templates() throws Exception { Map ret = new HashMap<>(); - ret.put("bucket", new RangerResourceNameParser("bucket", RRN_RESOURCE_SEP_CHAR)); - ret.put("path", new RangerResourceNameParser("bucket/path", RRN_RESOURCE_SEP_CHAR)); + ret.put("bucket", new RangerResourceNameParser("bucket")); + ret.put("path", new RangerResourceNameParser("bucket/path")); return ret; } @@ -326,8 +324,8 @@ private static Map getS3Templates() throws Exc private static Map getAdlsGen2Templates() throws Exception { Map ret = new HashMap<>(); - ret.put("container", new RangerResourceNameParser("storageaccount/container", RRN_RESOURCE_SEP_CHAR)); - ret.put("relativepath", new RangerResourceNameParser("storageaccount/container/relativepath", RRN_RESOURCE_SEP_CHAR)); + ret.put("container", new RangerResourceNameParser("storageaccount/container")); + ret.put("relativepath", new RangerResourceNameParser("storageaccount/container/relativepath")); return ret; } @@ -335,19 +333,19 @@ private static Map getAdlsGen2Templates() thro private static Map getTrinoTemplates() throws Exception { Map ret = new HashMap<>(); - ret.put("catalog", new RangerResourceNameParser("catalog", RRN_RESOURCE_SEP_CHAR)); - ret.put("schema", new RangerResourceNameParser("catalog/schema", RRN_RESOURCE_SEP_CHAR)); - ret.put("table", new RangerResourceNameParser("catalog/schema/table", RRN_RESOURCE_SEP_CHAR)); - ret.put("column", new RangerResourceNameParser("catalog/schema/table/column", RRN_RESOURCE_SEP_CHAR)); - ret.put("trinouser", new RangerResourceNameParser("trinouser", RRN_RESOURCE_SEP_CHAR)); - ret.put("systemproperty", new RangerResourceNameParser("systemproperty", RRN_RESOURCE_SEP_CHAR)); - ret.put("sessionproperty", new RangerResourceNameParser("catalog/sessionproperty", RRN_RESOURCE_SEP_CHAR)); - ret.put("function", new RangerResourceNameParser("function", RRN_RESOURCE_SEP_CHAR)); - ret.put("procedure", new RangerResourceNameParser("catalog/schema/procedure", RRN_RESOURCE_SEP_CHAR)); - ret.put("schemafunction", new RangerResourceNameParser("catalog/schema/schemafunction", RRN_RESOURCE_SEP_CHAR)); - ret.put("queryid", new RangerResourceNameParser("queryid", RRN_RESOURCE_SEP_CHAR)); - ret.put("sysinfo", new RangerResourceNameParser("sysinfo", RRN_RESOURCE_SEP_CHAR)); - ret.put("role", new RangerResourceNameParser("role", RRN_RESOURCE_SEP_CHAR)); + ret.put("catalog", new RangerResourceNameParser("catalog")); + ret.put("schema", new RangerResourceNameParser("catalog/schema")); + ret.put("table", new RangerResourceNameParser("catalog/schema/table")); + ret.put("column", new RangerResourceNameParser("catalog/schema/table/column")); + ret.put("trinouser", new RangerResourceNameParser("trinouser")); + ret.put("systemproperty", new RangerResourceNameParser("systemproperty")); + ret.put("sessionproperty", new RangerResourceNameParser("catalog/sessionproperty")); + ret.put("function", new RangerResourceNameParser("function")); + ret.put("procedure", new RangerResourceNameParser("catalog/schema/procedure")); + ret.put("schemafunction", new RangerResourceNameParser("catalog/schema/schemafunction")); + ret.put("queryid", new RangerResourceNameParser("queryid")); + ret.put("sysinfo", new RangerResourceNameParser("sysinfo")); + ret.put("role", new RangerResourceNameParser("role")); return ret; } diff --git a/authz-embedded/pom.xml b/authz-embedded/pom.xml new file mode 100644 index 0000000000..05377ee94c --- /dev/null +++ b/authz-embedded/pom.xml @@ -0,0 +1,80 @@ + + + + 4.0.0 + + + org.apache.ranger + ranger + 3.0.0-SNAPSHOT + .. + + + authz-embedded + Ranger Authorization - Embedded + + + UTF-8 + + + + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + + + + org.apache.ranger + ranger-audit-dest-hdfs + ${project.version} + + + + org.apache.ranger + ranger-audit-dest-solr + ${project.version} + + + + org.apache.ranger + ranger-authz-api + ${project.version} + + + + org.apache.ranger + ranger-plugins-common + ${project.version} + + + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + diff --git a/authz-embedded/src/conf/ranger-authz-embedded.properties b/authz-embedded/src/conf/ranger-authz-embedded.properties new file mode 100644 index 0000000000..1f6652bd1e --- /dev/null +++ b/authz-embedded/src/conf/ranger-authz-embedded.properties @@ -0,0 +1,64 @@ +# +# 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. +# + +ranger.authz.init.services=dev_hdfs,dev_hive,dev_kafka + +# Default service name for each service type - used when authz requests don't specify service name +ranger.authz.servicetype.hdfs.default.service=dev_hdfs +ranger.authz.servicetype.ozone.default.service=dev_ozone +ranger.authz.servicetype.hive.default.service=dev_hive +ranger.authz.servicetype.hbase.default.service=dev_hbase +ranger.authz.servicetype.trino.default.service=dev_trino +ranger.authz.servicetype.kafka.default.service=dev_kafka + +# Default source for policy information +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.RangerAdminRESTClient +ranger.authz.default.policy.rest.url=http://localhost:6080 +ranger.authz.default.policy.rest.ssl.config.file=/etc/hive/conf/ranger-policymgr-ssl.xml +ranger.authz.default.policy.rest.client.connection.timeoutMs=120000 +ranger.authz.default.policy.rest.client.read.timeoutMs=30000 +ranger.authz.default.policy.pollIntervalMs=30000 +ranger.authz.default.policy.cache.dir=/etc/ranger/policycache + +# Alternate source for policy information: embedded resources +# ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +# ranger.authz.default.policy.source.embedded_resource.path=/test_hive + +# Alternate source for policy information: local files +# ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.LocalFolderPolicySource +# ranger.authz.default.policy.source.local_folder.path=/home/ranger/authz_data + + +# Audit configurations +# Audit destination: HDFS +ranger.authz.audit.destination.hdfs=enabled +ranger.authz.audit.destination.hdfs.dir=hdfs://nameservice1/ranger/audit +ranger.authz.audit.destination.hdfs.subdir=%app-type%/%time:yyyyMMdd% +ranger.authz.audit.destination.hdfs.filename.format=ranger_audit_%hostname%.log +ranger.authz.audit.destination.hdfs.file.rollover.sec=86400 + +# Audit destination: Solr +ranger.authz.audit.destination.solr=enabled +ranger.authz.audit.destination.solr.urls=http://localhost:8983/solr +ranger.authz.audit.destination.solr.zookeepers= +ranger.authz.audit.destination.solr.collection=ranger_audits + +# Audit destination: Log4j +ranger.authz.audit.destination.log4j=enabled +ranger.authz.audit.destination.log4j.logger=ranger_audit + diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java new file mode 100644 index 0000000000..a16c5ede64 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzAuditHandler.java @@ -0,0 +1,69 @@ +/* + * 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.ranger.authz.embedded; + +import org.apache.ranger.audit.model.AuthzAuditEvent; +import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import java.util.ArrayList; +import java.util.Collection; + +public class RangerAuthzAuditHandler extends RangerDefaultAuditHandler implements AutoCloseable { + private final RangerBasePlugin plugin; + private final Collection auditEvents = new ArrayList<>(); + private boolean deniedExists; + + public RangerAuthzAuditHandler(RangerBasePlugin plugin) { + super(); + + this.plugin = plugin; + } + + @Override + public void processResult(RangerAccessResult result) { + if (!deniedExists) { // if a denied audit already exists, ignore all others + AuthzAuditEvent auditEvent = getAuthzEvents(result); + + if (auditEvent != null) { + auditEvent.setAgentId(plugin.getAppId()); + + if (result.getIsAccessDetermined() && !result.getIsAllowed()) { + deniedExists = true; + + auditEvents.clear(); + } + + auditEvents.add(auditEvent); + } + } + } + + @Override + public void processResults(Collection results) { + results.forEach(this::processResult); + } + + @Override + public void close() { + auditEvents.forEach(super::logAuthzAudit); + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java new file mode 100644 index 0000000000..71ba854a88 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzConfig.java @@ -0,0 +1,123 @@ +/* + * 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.ranger.authz.embedded; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Properties; + +public class RangerAuthzConfig { + public static final String PROP_PREFIX_INIT_SERVICES = "ranger.authz.init.services"; + public static final String PROP_PREFIX_DEFAULT = "ranger.authz.default."; + public static final String PROP_PREFIX_AUDIT = "ranger.authz.audit."; + public static final String PROP_PREFIX_SERVICE = "ranger.authz.service."; + public static final String PROP_PREFIX_SERVICE_TYPE = "ranger.authz.servicetype."; + + private final Properties properties; + + public RangerAuthzConfig(Properties properties) { + this.properties = properties; + } + + public String[] getInitServices() { + String initServices = properties.getProperty(PROP_PREFIX_INIT_SERVICES); + + if (StringUtils.isBlank(initServices)) { + return new String[0]; + } + + return initServices.split(","); + } + + public Properties getAuditProperties() { + Properties ret = new Properties(); + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(PROP_PREFIX_AUDIT)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(PROP_PREFIX_AUDIT.length()); + String pluginPropName = "xasecure.audit." + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + return ret; + } + + public Properties getServiceProperties(String serviceName, String serviceType) { + Properties ret = new Properties(); + + if (StringUtils.isBlank(serviceType)) { + serviceType = getServiceTypeForService(serviceName); + } + + String pluginPropPrefix = "ranger.plugin." + serviceType + "."; + + // collect default properties + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(PROP_PREFIX_DEFAULT)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(PROP_PREFIX_DEFAULT.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + // collect service-type level properties + if (StringUtils.isNotBlank(serviceType)) { + String svcTypePropPrefix = PROP_PREFIX_SERVICE_TYPE + serviceType + "."; + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(svcTypePropPrefix)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(svcTypePropPrefix.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + } + + // collect service-level properties + String svcPropPrefix = PROP_PREFIX_SERVICE + serviceName + "."; + + for (String propName : properties.stringPropertyNames()) { + if (propName.startsWith(svcPropPrefix)) { + String propValue = properties.getProperty(propName); + String propSuffix = propName.substring(svcPropPrefix.length()); + String pluginPropName = pluginPropPrefix + propSuffix; + + ret.setProperty(pluginPropName, propValue); + } + } + + return ret; + } + + public String getServiceTypeForService(String serviceName) { + return properties.getProperty(PROP_PREFIX_SERVICE + serviceName + ".servicetype"); + } + + public String getDefaultServiceNameForServiceType(String serviceType) { + return properties.getProperty(PROP_PREFIX_SERVICE_TYPE + serviceType + ".default.service"); + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java new file mode 100644 index 0000000000..ba0a55af7c --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerAuthzPlugin.java @@ -0,0 +1,409 @@ +/* + * 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.ranger.authz.embedded; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; +import org.apache.ranger.authz.api.RangerAuthzApiErrorCode; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAccessInfo; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessDecision; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessResult; +import org.apache.ranger.authz.model.RangerAuthzResult.DataMaskResult; +import org.apache.ranger.authz.model.RangerAuthzResult.PermissionResult; +import org.apache.ranger.authz.model.RangerAuthzResult.PolicyInfo; +import org.apache.ranger.authz.model.RangerAuthzResult.ResultInfo; +import org.apache.ranger.authz.model.RangerAuthzResult.RowFilterResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.apache.ranger.authz.model.RangerUserInfo; +import org.apache.ranger.authz.util.RangerResourceNameParser; +import org.apache.ranger.plugin.model.RangerPolicy; +import org.apache.ranger.plugin.model.validation.RangerServiceDefHelper; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerResourceACLs; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.RangerAccessRequestUtil; +import org.apache.ranger.plugin.util.ServicePolicies; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; + +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_ALLOWED; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_CONDITIONAL; +import static org.apache.ranger.plugin.policyevaluator.RangerPolicyEvaluator.ACCESS_DENIED; + +public class RangerAuthzPlugin { + private static final Logger LOG = LoggerFactory.getLogger(RangerAuthzPlugin.class); + + private final RangerBasePlugin plugin; + private final Map rrnTemplates = new HashMap<>(); + + public RangerAuthzPlugin(String serviceType, String serviceName, Properties properties) { + plugin = new RangerBasePlugin(getPluginConfig(serviceType, serviceName, properties)) { + @Override + public void setPolicies(ServicePolicies policies) { + super.setPolicies(policies); + + updateResourceTemplates(); + } + }; + + plugin.init(); + } + + public void cleanup() { + plugin.cleanup(); + } + + public RangerAuthzResult authorize(RangerAuthzRequest request, RangerAuthzAuditHandler auditHandler) throws RangerAuthzException { + RangerUserInfo userInfo = request.getUser(); + RangerAccessInfo access = request.getAccess(); + RangerAccessContext context = request.getContext(); + Set permissions = access.getPermissions(); + RangerAuthzResult ret = new RangerAuthzResult(request.getRequestId(), new HashMap<>(permissions.size())); + RangerAccessResource resource = getResource(access.getResource().getName(), access.getResource().getAttributes()); + RangerAccessRequestImpl accessRequest = new RangerAccessRequestImpl(resource, null, userInfo.getName(), userInfo.getGroups(), userInfo.getRoles()); + + initializeRequest(accessRequest, context); + + boolean hasDeny = false; + boolean hasAllow = false; + boolean hasNotDetermined = false; + + for (String permission : permissions) { + accessRequest.setAccessType(permission); + accessRequest.setContext(new HashMap<>(context.getAdditionalInfo())); + + ResultInfo result = evaluate(accessRequest, auditHandler); + PermissionResult permResult = new PermissionResult(permission, result); + + if (CollectionUtils.isNotEmpty(access.getResource().getSubResources())) { + permResult.setAccess(new AccessResult()); // when sub-resources are evaluated, top-level resource's access is derived from sub-resources + permResult.setSubResources(new HashMap<>(access.getResource().getSubResources().size())); + + for (String subResourceName : access.getResource().getSubResources()) { + accessRequest.setResource(getSubResource(resource, subResourceName)); + accessRequest.setContext(new HashMap<>(context.getAdditionalInfo())); // reset the context + + ResultInfo subResourceResult = evaluate(accessRequest, auditHandler); + + updateResult(subResourceResult.getAccess(), permResult.getAccess()); + + permResult.getSubResources().put(subResourceName, subResourceResult); + } + } + + if (permResult.getAccess().getDecision() == AccessDecision.DENY) { + permResult.setDataMask(null); + permResult.setRowFilter(null); + } + + ret.getPermissions().put(permission, permResult); + + AccessDecision permDecision = permResult.getAccess() == null ? AccessDecision.NOT_DETERMINED : permResult.getAccess().getDecision(); + + if (permDecision == AccessDecision.DENY) { + hasDeny = true; + } else if (permDecision == AccessDecision.ALLOW) { + hasAllow = true; + } else { + hasNotDetermined = true; + } + } + + if (hasDeny) { + ret.setDecision(AccessDecision.DENY); + } else if (hasNotDetermined) { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } else if (hasAllow) { + ret.setDecision(AccessDecision.ALLOW); + } + + return ret; + } + + public RangerResourcePermissions getResourcePermissions(RangerResourceInfo resource, RangerAccessContext context) throws RangerAuthzException { + RangerResourcePermissions ret = new RangerResourcePermissions(); + RangerAccessRequestImpl request = new RangerAccessRequestImpl(); + + ret.setResource(resource); + request.setResource(getResource(resource.getName(), null)); + initializeRequest(request, context); + + RangerResourceACLs acls = plugin.getResourceACLs(request); + + if (acls != null) { + for (Map.Entry> entry : acls.getUserACLs().entrySet()) { + String userName = entry.getKey(); + Map userAcls = entry.getValue(); + + if (userAcls != null) { + for (Map.Entry aclEntry : userAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setUserPermission(userName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + + for (Map.Entry> entry : acls.getGroupACLs().entrySet()) { + String groupName = entry.getKey(); + Map groupAcls = entry.getValue(); + + if (groupAcls != null) { + for (Map.Entry aclEntry : groupAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setGroupPermission(groupName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + + for (Map.Entry> entry : acls.getRoleACLs().entrySet()) { + String roleName = entry.getKey(); + Map roleAcls = entry.getValue(); + + if (roleAcls != null) { + for (Map.Entry aclEntry : roleAcls.entrySet()) { + String permission = aclEntry.getKey(); + RangerResourceACLs.AccessResult acl = aclEntry.getValue(); + + ret.setRolePermission(roleName, permission, new PermissionResult(permission, new ResultInfo(toAccessResult(acl), null, null, null))); + } + } + } + } + + return ret; + } + + RangerBasePlugin getPlugin() { + return plugin; + } + + private RangerAccessResource getResource(String resource, Map attributes) throws RangerAuthzException { + Map resourceMap = getResourceAsMap(resource); + Object ownerName = attributes != null ? attributes.get(RangerAccessRequestUtil.KEY_OWNER) : null; + + return new RangerAccessResourceImpl(resourceMap, ownerName != null ? ownerName.toString() : null); + } + + private RangerAccessResource getSubResource(RangerAccessResource parent, String subResourceName) { + Map elements = new HashMap<>(parent.getAsMap()); + + if (StringUtils.isNotBlank(subResourceName)) { + String[] parts = subResourceName.split(":", 2); + + elements.put(parts[0], parts.length > 1 ? parts[1] : ""); + } + + return new RangerAccessResourceImpl(elements, parent.getOwnerUser()); + } + + private void initializeRequest(RangerAccessRequestImpl request, RangerAccessContext context) { + request.setAccessTime(new Date(context.getAccessTime())); + request.setClientIPAddress(context.getClientIpAddress()); + request.setForwardedAddresses(context.getForwardedIpAddresses()); + request.setClientType(getClientType(context.getAdditionalInfo())); + request.setClusterType(getClusterType(context.getAdditionalInfo())); + request.setClusterName(getClusterName(context.getAdditionalInfo())); + request.setRequestData(getRequestData(context.getAdditionalInfo())); + request.setContext(new HashMap<>(context.getAdditionalInfo())); + } + + private String getClientType(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLIENT_TYPE) : null; + + return ret != null ? ret.toString() : null; + } + + private String getClusterType(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLUSTER_TYPE) : null; + + return ret != null ? ret.toString() : null; + } + + private String getClusterName(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_CLUSTER_NAME) : null; + + return ret != null ? ret.toString() : null; + } + + private String getRequestData(Map context) { + Object ret = context != null ? context.get(RangerAccessContext.CONTEXT_INFO_REQUEST_DATA) : null; + + return ret != null ? ret.toString() : null; + } + + private void updateResult(AccessResult from, AccessResult to) { + if (from == null || to == null || from.getDecision() == null || + to.getDecision() == from.getDecision() || // no change in decision + to.getDecision() == AccessDecision.DENY) { // don't override earlier DENY + return; + } + + if (to.getDecision() == null || from.getDecision() == AccessDecision.DENY || from.getDecision() == AccessDecision.NOT_DETERMINED) { + to.setDecision(from.getDecision()); + to.setPolicy(from.getPolicy()); + } + } + + private ResultInfo toPermissionResult(RangerAccessResult result) { + ResultInfo ret = new ResultInfo(toAccessResult(result), null, null, null); + + if (result.getPolicyType() == RangerPolicy.POLICY_TYPE_DATAMASK) { + ret.setDataMask(new DataMaskResult(result.getMaskType(), result.getMaskedValue(), ret.getAccess().getPolicy())); + } else if (result.getPolicyType() == RangerPolicy.POLICY_TYPE_ROWFILTER) { + ret.setRowFilter(new RowFilterResult(result.getFilterExpr(), ret.getAccess().getPolicy())); + } + + return ret; + } + + private AccessResult toAccessResult(RangerResourceACLs.AccessResult result) { + AccessResult ret = new AccessResult(); + + if (result != null) { + if (result.getIsFinal()) { + if (result.getResult() == ACCESS_ALLOWED) { + ret.setDecision(AccessDecision.ALLOW); + } else if (result.getResult() == ACCESS_DENIED) { + ret.setDecision(AccessDecision.DENY); + } else if (result.getResult() == ACCESS_CONDITIONAL) { + ret.setDecision(AccessDecision.DENY); // TODO: introduce a new AccessDecision.CONDITIONAL + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + + if (result.getPolicy() != null) { + ret.setPolicy(new PolicyInfo(result.getPolicy().getId(), result.getPolicy().getVersion())); + } else { + ret.setPolicy(null); + } + } + + return ret; + } + + private AccessResult toAccessResult(RangerAccessResult result) { + AccessResult ret = new AccessResult(); + + if (result.getIsAccessDetermined()) { + ret.setDecision(result.getIsAllowed() ? AccessDecision.ALLOW : AccessDecision.DENY); + } else { + ret.setDecision(AccessDecision.NOT_DETERMINED); + } + + ret.setPolicy(toPolicyInfo(result)); + + return ret; + } + + private PolicyInfo toPolicyInfo(RangerAccessResult result) { + return new PolicyInfo(result.getPolicyId(), result.getPolicyVersion()); + } + + private ResultInfo evaluate(RangerAccessRequest request, RangerAuthzAuditHandler auditHandler) { + RangerAccessResult result = plugin.isAccessAllowed(request, auditHandler); + ResultInfo ret = toPermissionResult(result); + + if (plugin.getServiceDefHelper().isRowFilterSupported(request.getResource().getKeys())) { + RangerAccessResult rowFilterResult = plugin.evalRowFilterPolicies(request, auditHandler); + + if (rowFilterResult != null && rowFilterResult.getIsAccessDetermined() && StringUtils.isNotBlank(rowFilterResult.getFilterExpr())) { + ret.setRowFilter(new RowFilterResult(rowFilterResult.getFilterExpr(), toPolicyInfo(rowFilterResult))); + } + } + + if (plugin.getServiceDefHelper().isDataMaskSupported(request.getResource().getKeys())) { + RangerAccessResult dataMaskResult = plugin.evalDataMaskPolicies(request, auditHandler); + + if (dataMaskResult != null && dataMaskResult.getIsAccessDetermined() && StringUtils.isNotBlank(dataMaskResult.getMaskType())) { + ret.setDataMask(new DataMaskResult(dataMaskResult.getMaskType(), dataMaskResult.getMaskedValue(), toPolicyInfo(dataMaskResult))); + } + } + + return ret; + } + + private Map getResourceAsMap(String resource) throws RangerAuthzException { + String[] resourceParts = resource.split(":", 2); + String resourceType = resourceParts.length > 0 ? resourceParts[0] : null; + String resourceValue = resourceParts.length > 1 ? resourceParts[1] : null; + RangerResourceNameParser template = rrnTemplates.get(resourceType); + + if (template == null) { + throw new RangerAuthzException(RangerAuthzApiErrorCode.INVALID_REQUEST_RESOURCE_TYPE_NOT_FOUND, resourceType); + } + + Map ret = template.parseToMap(resourceValue); + + if (ret == null) { + throw new RangerAuthzException(RangerAuthzApiErrorCode.INVALID_REQUEST_RESOURCE_VALUE_FOR_TYPE, resourceValue, resourceType); + } + + return (Map) ret; + } + + private void updateResourceTemplates() { + RangerServiceDefHelper serviceDefHelper = plugin.getServiceDefHelper(); + + if (serviceDefHelper != null) { + for (String resourceType : serviceDefHelper.getAllResourceNames()) { + String rrnTemplate = serviceDefHelper.getRrnTemplate(resourceType); + RangerResourceNameParser existing = rrnTemplates.get(resourceType); + + if (existing == null || !Objects.equals(existing.getTemplate(), rrnTemplate)) { + LOG.info("updateResourceTemplates(): resourceType={} updated to rrnTemplate={}", resourceType, rrnTemplate); + + try { + rrnTemplates.put(resourceType, new RangerResourceNameParser(rrnTemplate)); + } catch (RangerAuthzException excp) { + LOG.warn("updateResourceTemplates(): failed to create resource template for resourceType={}, rrnTemplate={}", resourceType, rrnTemplate, excp); + } + } + } + } + } + + private static RangerPluginConfig getPluginConfig(String serviceType, String serviceName, Properties properties) { + return new RangerPluginConfig(serviceType, serviceName, null, properties); + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java new file mode 100644 index 0000000000..d76d04a461 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthorizer.java @@ -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.ranger.authz.embedded; + +import org.apache.commons.lang3.StringUtils; +import org.apache.ranger.audit.provider.AuditProviderFactory; +import org.apache.ranger.authz.api.RangerAuthorizer; +import org.apache.ranger.authz.api.RangerAuthzException; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAccessInfo; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerAuthzResult.AccessDecision; +import org.apache.ranger.authz.model.RangerMultiAuthzRequest; +import org.apache.ranger.authz.model.RangerMultiAuthzResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static org.apache.ranger.authz.api.RangerAuthzApiErrorCode.INVALID_REQUEST_SERVICE_NAME_OR_TYPE_MANDATORY; +import static org.apache.ranger.authz.embedded.RangerEmbeddedAuthzErrorCode.NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE; +import static org.apache.ranger.authz.embedded.RangerEmbeddedAuthzErrorCode.NO_SERVICE_TYPE_FOR_SERVICE; + +public class RangerEmbeddedAuthorizer extends RangerAuthorizer { + private static final Logger LOG = LoggerFactory.getLogger(RangerEmbeddedAuthorizer.class); + + private final RangerAuthzConfig config; + private final Map plugins = new HashMap<>(); + + public RangerEmbeddedAuthorizer(Properties properties) { + super(properties); + + this.config = new RangerAuthzConfig(properties); + } + + @Override + public void init() throws RangerAuthzException { + AuditProviderFactory.getInstance().init(config.getAuditProperties(), "ranger-authz"); + + String[] initServices = config.getInitServices(); + + for (String serviceName : initServices) { + String serviceType = config.getServiceTypeForService(serviceName); + + getOrCreatePlugin(serviceName, serviceType); + } + } + + @Override + public void close() { + for (RangerAuthzPlugin plugin : plugins.values()) { + plugin.cleanup(); + } + + plugins.clear(); + } + + @Override + public RangerAuthzResult authorize(RangerAuthzRequest request) throws RangerAuthzException { + validateRequest(request); + + RangerAuthzPlugin plugin = getOrCreatePlugin(request.getContext().getServiceName(), request.getContext().getServiceType()); + + try (RangerAuthzAuditHandler auditHandler = new RangerAuthzAuditHandler(plugin.getPlugin())) { + return authorize(request, plugin, auditHandler); + } + } + + @Override + public RangerMultiAuthzResult authorize(RangerMultiAuthzRequest request) throws RangerAuthzException { + validateRequest(request); + + RangerAuthzPlugin plugin = getOrCreatePlugin(request.getContext().getServiceName(), request.getContext().getServiceType()); + RangerMultiAuthzResult result = new RangerMultiAuthzResult(request.getRequestId()); + + if (request.getAccesses() != null) { + int allowedCount = 0; + int deniedCount = 0; + int notDeterminedCount = 0; + + result.setAccesses(new ArrayList<>(request.getAccesses().size())); + + try (RangerAuthzAuditHandler auditHandler = new RangerAuthzAuditHandler(plugin.getPlugin())) { + for (RangerAccessInfo accessInfo : request.getAccesses()) { + RangerAuthzRequest authzRequest = new RangerAuthzRequest(null, request.getUser(), accessInfo, request.getContext()); + RangerAuthzResult authzResult = authorize(authzRequest, plugin, auditHandler); + + if (authzResult.getDecision() == AccessDecision.ALLOW) { + allowedCount++; + } else if (authzResult.getDecision() == AccessDecision.DENY) { + deniedCount++; + } else if (authzResult.getDecision() == AccessDecision.NOT_DETERMINED) { + notDeterminedCount++; + } + + result.getAccesses().add(authzResult); + } + } + + if (allowedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.ALLOW); + } else if (deniedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.DENY); + } else if (notDeterminedCount == request.getAccesses().size()) { + result.setDecision(AccessDecision.NOT_DETERMINED); + } else { + result.setDecision(AccessDecision.PARTIAL); + } + } + + return result; + } + + @Override + public RangerResourcePermissions getResourcePermissions(RangerResourceInfo resource, RangerAccessContext context) throws RangerAuthzException { + validateAccessContext(context); + + RangerAuthzPlugin plugin = getOrCreatePlugin(context.getServiceName(), context.getServiceType()); + + return plugin.getResourcePermissions(resource, context); + } + + @Override + protected void validateAccessContext(RangerAccessContext context) throws RangerAuthzException { + super.validateAccessContext(context); + + String serviceName = context.getServiceName(); + String serviceType = context.getServiceType(); + + if (StringUtils.isBlank(serviceName)) { + if (StringUtils.isBlank(serviceType)) { + throw new RangerAuthzException(INVALID_REQUEST_SERVICE_NAME_OR_TYPE_MANDATORY); + } + + serviceName = config.getDefaultServiceNameForServiceType(serviceType); + + if (StringUtils.isBlank(serviceName)) { + throw new RangerAuthzException(NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE, serviceName); + } + + context.setServiceName(serviceName); + } + + if (StringUtils.isBlank(serviceType)) { + serviceType = config.getServiceTypeForService(serviceName); + + if (StringUtils.isBlank(serviceType)) { + throw new RangerAuthzException(NO_SERVICE_TYPE_FOR_SERVICE, serviceName); + } + + context.setServiceType(serviceType); + } + } + + private RangerAuthzResult authorize(RangerAuthzRequest request, RangerAuthzPlugin plugin, RangerAuthzAuditHandler auditHandler) throws RangerAuthzException { + return plugin.authorize(request, auditHandler); + } + + private RangerAuthzPlugin getOrCreatePlugin(String serviceName, String serviceType) throws RangerAuthzException { + RangerAuthzPlugin ret = plugins.get(serviceName); + + if (ret == null) { + synchronized (plugins) { + ret = plugins.get(serviceName); + + if (ret == null) { + Properties pluginProperties = this.config.getServiceProperties(serviceName, serviceType); + + LOG.debug("properties for service {}: {}", serviceName, pluginProperties); + + ret = new RangerAuthzPlugin(serviceType, serviceName, pluginProperties); + + plugins.put(serviceName, ret); + } + } + } + + return ret; + } +} diff --git a/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java new file mode 100644 index 0000000000..4028298216 --- /dev/null +++ b/authz-embedded/src/main/java/org/apache/ranger/authz/embedded/RangerEmbeddedAuthzErrorCode.java @@ -0,0 +1,63 @@ +/* + * 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.ranger.authz.embedded; + +import org.apache.ranger.authz.api.RangerAuthzErrorCode; + +public enum RangerEmbeddedAuthzErrorCode implements RangerAuthzErrorCode { + NO_SERVICE_TYPE_FOR_SERVICE(400, "00-001", "No service type found for service {0}"), + NO_DEFAULT_SERVICE_FOR_SERVICE_TYPE(400, "00-002", "No default service found for service type {0}"), + + FAILED_TO_CONTACT_AUTHZ_SERVICE(404, "00-001", "Failed to contact authorization service"), + FAILED_TO_GET_SERVICE_POLICIES(404, "00-002", "Failed to retrieve policies for service {0}"); + + private static final String ERROR_CODE_MODULE_PREFIX = "E_AUTHZ-"; + + private final int httpStatusCode; + private final String code; + private final String message; + + RangerEmbeddedAuthzErrorCode(int httpStatusCode, String code, String message) { + this.httpStatusCode = httpStatusCode; + this.code = String.format("%s-%3d-%s", ERROR_CODE_MODULE_PREFIX, httpStatusCode, code); + this.message = message; + } + + public int getHttpStatusCode() { + return httpStatusCode; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "RangerEmbeddedAuthzErrorCode{" + + "httpStatusCode=" + httpStatusCode + + ", code='" + code + '\'' + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java new file mode 100644 index 0000000000..5636ae3c20 --- /dev/null +++ b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestEmbeddedAuthorizer.java @@ -0,0 +1,205 @@ +/* + * 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.ranger.authz.embedded; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ranger.authz.model.RangerAccessContext; +import org.apache.ranger.authz.model.RangerAuthzRequest; +import org.apache.ranger.authz.model.RangerAuthzResult; +import org.apache.ranger.authz.model.RangerMultiAuthzRequest; +import org.apache.ranger.authz.model.RangerMultiAuthzResult; +import org.apache.ranger.authz.model.RangerResourceInfo; +import org.apache.ranger.authz.model.RangerResourcePermissions; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestEmbeddedAuthorizer { + private static final TypeReference> TYPE_LIST_TEST_AUTHZ_DATA = new TypeReference>() {}; + private static final TypeReference> TYPE_LIST_TEST_MULTI_AUTHZ_DATA = new TypeReference>() {}; + private static final TypeReference> TYPE_LIST_TEST_RESOURCE_PERMISSIONS_DATA = new TypeReference>() {}; + + @Test + public void testAuthzS3() throws Exception { + runAuthzTest("test_s3"); + } + + @Test + public void testMultiAuthzS3() throws Exception { + runMultiAuthzTest("test_s3"); + } + + @Test + public void testResourcePermissionsS3() throws Exception { + runResourcePermissionsTest("test_s3"); + } + + @Test + public void testAuthzHive() throws Exception { + runAuthzTest("test_hive"); + } + + @Test + public void testResourcePermissionsHive() throws Exception { + runResourcePermissionsTest("test_hive"); + } + + private void runResourcePermissionsTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_resource_permissions.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestResourcePermissionsData test : loadTestResourcePermissionsData(testsPath)) { + if (test.resource == null || test.context == null || test.permissions == null) { + continue; + } + + RangerResourcePermissions permissions = authorizer.getResourcePermissions(test.resource, test.context); + + assertEquals(test.permissions, permissions, "Resource permissions do not match for resource=" + test.resource); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private void runAuthzTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_authz.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestAuthzData test : loadTestAuthzData(testsPath)) { + if (test.request == null || test.result == null) { + continue; + } + + RangerAuthzRequest request = test.request; + RangerAuthzResult expected = test.result; + RangerAuthzResult result = authorizer.authorize(request); + + assertEquals(expected, result); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private void runMultiAuthzTest(String testName) throws Exception { + String propertiesPath = "/" + testName + "/ranger-embedded-authz.properties"; + String testsPath = "/" + testName + "/tests_multi_authz.json"; + + RangerEmbeddedAuthorizer authorizer = null; + + try { + authorizer = new RangerEmbeddedAuthorizer(loadProperties(propertiesPath)); + + authorizer.init(); + + for (TestMultiAuthzData test : loadTestMultiAuthzData(testsPath)) { + if (test.request == null || test.result == null) { + continue; + } + + RangerMultiAuthzRequest request = test.request; + RangerMultiAuthzResult expected = test.result; + RangerMultiAuthzResult result = authorizer.authorize(request); + + assertEquals(expected, result); + } + } finally { + if (authorizer != null) { + authorizer.close(); + } + } + } + + private Properties loadProperties(String resourcePath) throws Exception { + Properties properties = new Properties(); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + properties.load(in); + } + + return properties; + } + + private List loadTestAuthzData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return mapper.readValue(in, TYPE_LIST_TEST_AUTHZ_DATA); + } + } + + private List loadTestMultiAuthzData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return in != null ? mapper.readValue(in, TYPE_LIST_TEST_MULTI_AUTHZ_DATA) : Collections.emptyList(); + } + } + + private List loadTestResourcePermissionsData(String resourcePath) throws Exception { + ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + try (InputStream in = getClass().getResourceAsStream(resourcePath)) { + return in != null ? mapper.readValue(in, TYPE_LIST_TEST_RESOURCE_PERMISSIONS_DATA) : Collections.emptyList(); + } + } + + private static class TestAuthzData { + public RangerAuthzRequest request; + public RangerAuthzResult result; + } + + private static class TestMultiAuthzData { + public RangerMultiAuthzRequest request; + public RangerMultiAuthzResult result; + } + + private static class TestResourcePermissionsData { + public RangerResourceInfo resource; + public RangerAccessContext context; + public RangerResourcePermissions permissions; + } +} diff --git a/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java new file mode 100644 index 0000000000..fd9c77a1bd --- /dev/null +++ b/authz-embedded/src/test/java/org/apache/ranger/authz/embedded/TestRangerAuthzConfig.java @@ -0,0 +1,231 @@ +/* + * 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.ranger.authz.embedded; + +import org.junit.jupiter.api.Test; + +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TestRangerAuthzConfig { + @Test + public void testEmptyConfig() { + RangerAuthzConfig config = new RangerAuthzConfig(new Properties()); + + assertTrue(config.getServiceProperties("dev_hive", "hive").isEmpty()); + assertTrue(config.getServiceProperties("prod_hive", "hive").isEmpty()); + assertTrue(config.getServiceProperties("dev_hdfs", "hdfs").isEmpty()); + assertTrue(config.getAuditProperties().isEmpty()); + } + + @Test + public void testDefaultConfigs() { + RangerAuthzConfig config = new RangerAuthzConfig(createDefaultProperties()); + + validateDevHiveProperties(config.getServiceProperties("dev_hive", "hive")); + validateProdHiveProperties(config.getServiceProperties("prod_hive", "hive")); + validateDevHdfsProperties(config.getServiceProperties("dev_hdfs", "hdfs")); + } + + @Test + public void testAuditConfigsV2() { + RangerAuthzConfig config = new RangerAuthzConfig(createAuditV2Properties()); + Properties auditProperties = config.getAuditProperties(); + + assertEquals(23, auditProperties.size()); + + validateAuditConfigV2(auditProperties); + } + + @Test + public void testAuditConfigsV3() { + RangerAuthzConfig config = new RangerAuthzConfig(createAuditV3Properties()); + Properties auditProperties = config.getAuditProperties(); + + assertEquals(10, auditProperties.size()); + + validateAuditConfigV3(auditProperties); + } + + @Test + public void testAllAuthzConfigs() { + RangerAuthzConfig config = new RangerAuthzConfig(createAllAuthzProperties()); + + validateDevHiveProperties(config.getServiceProperties("dev_hive", "hive")); + validateProdHiveProperties(config.getServiceProperties("prod_hive", "hive")); + validateDevHdfsProperties(config.getServiceProperties("dev_hdfs", "hdfs")); + validateAuditConfigV2(config.getAuditProperties()); + validateAuditConfigV3(config.getAuditProperties()); + } + + private void validateDevHiveProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hive.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hive.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hive.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hive.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hive.policy.cache.dir")); + } + + private void validateProdHiveProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hive.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hive.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hive.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hive.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hive.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hive.policy.cache.dir")); + } + + private void validateDevHdfsProperties(Properties prop) { + assertEquals(7, prop.size()); + assertEquals("org.apache.ranger.admin.client.RangerAdminRESTClient", prop.getProperty("ranger.plugin.hdfs.policy.source.impl")); + assertEquals("http://localhost:6080", prop.getProperty("ranger.plugin.hdfs.policy.rest.url")); + assertEquals("/etc/hive/conf/ranger-policymgr-ssl.xml", prop.getProperty("ranger.plugin.hdfs.policy.rest.ssl.config.file")); + assertEquals("120000", prop.getProperty("ranger.plugin.hdfs.policy.rest.client.connection.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hdfs.policy.rest.client.read.timeoutMs")); + assertEquals("30000", prop.getProperty("ranger.plugin.hdfs.policy.pollIntervalMs")); + assertEquals("/etc/ranger/policycache", prop.getProperty("ranger.plugin.hdfs.policy.cache.dir")); + } + + private void validateAuditConfigV2(Properties prop) { + assertEquals("true", prop.getProperty("xasecure.audit.is.enabled")); + assertEquals("false", prop.getProperty("xasecure.audit.hdfs.is.enabled")); + assertEquals("true", prop.getProperty("xasecure.audit.solr.is.enabled")); + assertEquals("false", prop.getProperty("xasecure.audit.log4j.is.enabled")); + + assertEquals("true", prop.getProperty("xasecure.audit.hdfs.is.async")); + assertEquals("1048576", prop.getProperty("xasecure.audit.hdfs.async.max.queue.size")); + assertEquals("30000", prop.getProperty("xasecure.audit.hdfs.async.max.flush.interval.ms")); + assertEquals("hdfs://namenode:8020/ranger/audit/%app-type%/%time:yyyyMMdd%", prop.getProperty("xasecure.audit.hdfs.config.destination.directory")); + assertEquals("%hostname%-audit.log", prop.getProperty("xasecure.audit.hdfs.config.destination.file")); + assertEquals("900", prop.getProperty("xasecure.audit.hdfs.config.destination.flush.interval.seconds")); + assertEquals("86400", prop.getProperty("xasecure.audit.hdfs.config.destination.rollover.interval.seconds")); + assertEquals("60", prop.getProperty("xasecure.audit.hdfs.config.destination.open.retry.interval.seconds")); + assertEquals("/var/log/hbase/audit/%app-type%", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.directory")); + assertEquals("%time:yyyyMMdd-HHmm.ss%.log", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.file")); + assertEquals("8192", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.file.buffer.size.bytes")); + assertEquals("60", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.flush.interval.seconds")); + assertEquals("600", prop.getProperty("xasecure.audit.hdfs.config.local.buffer.rollover.interval.seconds")); + assertEquals("/var/log/hbase/audit/archive/%app-type%", prop.getProperty("xasecure.audit.hdfs.config.local.archive.directory")); + assertEquals("10", prop.getProperty("xasecure.audit.hdfs.config.local.archive.max.file.count")); + + assertEquals("true", prop.getProperty("xasecure.audit.solr.is.async")); + assertEquals("1", prop.getProperty("xasecure.audit.solr.async.max.queue.size")); + assertEquals("1000", prop.getProperty("xasecure.audit.solr.async.max.flush.interval.ms")); + assertEquals("http://localhost:6083/solr/ranger_audits", prop.getProperty("xasecure.audit.solr.solr_url")); + } + + private void validateAuditConfigV3(Properties props) { + assertEquals("true", props.getProperty("xasecure.audit.is.enabled")); + assertEquals("false", props.getProperty("xasecure.audit.destination.hdfs")); + assertEquals("true", props.getProperty("xasecure.audit.destination.solr")); + assertEquals("false", props.getProperty("xasecure.audit.destination.log4j")); + + assertEquals("hdfs://namenode:8020/ranger/audit", props.getProperty("xasecure.audit.destination.hdfs.dir")); + assertEquals("%app-type%/%time:yyyyMMdd%", props.getProperty("xasecure.audit.destination.hdfs.subdir")); + assertEquals("%app-type%_ranger_audit_%hostname%.log", props.getProperty("xasecure.audit.destination.hdfs.filename.format")); + assertEquals("org.apache.ranger.audit.utils.RangerJSONAuditWriter", props.getProperty("xasecure.audit.destination.hdfs.filewriter.impl")); + + assertEquals("http://localhost:6083/solr/ranger_audits", props.getProperty("xasecure.audit.destination.solr.urls")); + assertEquals("ranger_audits", props.getProperty("xasecure.audit.destination.solr.collection")); + } + + private static Properties createDefaultProperties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.default.policy.source.impl", "org.apache.ranger.admin.client.RangerAdminRESTClient"); + props.setProperty("ranger.authz.default.policy.rest.url", "http://localhost:6080"); + props.setProperty("ranger.authz.default.policy.rest.ssl.config.file", "/etc/hive/conf/ranger-policymgr-ssl.xml"); + props.setProperty("ranger.authz.default.policy.rest.client.connection.timeoutMs", "120000"); + props.setProperty("ranger.authz.default.policy.rest.client.read.timeoutMs", "30000"); + props.setProperty("ranger.authz.default.policy.pollIntervalMs", "30000"); + props.setProperty("ranger.authz.default.policy.cache.dir", "/etc/ranger/policycache"); + + return props; + } + + private static Properties createAuditV2Properties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.audit.is.enabled", "true"); + props.setProperty("ranger.authz.audit.hdfs.is.enabled", "false"); + props.setProperty("ranger.authz.audit.solr.is.enabled", "true"); + props.setProperty("ranger.authz.audit.log4j.is.enabled", "false"); + + props.setProperty("ranger.authz.audit.hdfs.is.async", "true"); + props.setProperty("ranger.authz.audit.hdfs.async.max.queue.size", "1048576"); + props.setProperty("ranger.authz.audit.hdfs.async.max.flush.interval.ms", "30000"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.directory", "hdfs://namenode:8020/ranger/audit/%app-type%/%time:yyyyMMdd%"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.file", "%hostname%-audit.log"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.flush.interval.seconds", "900"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.rollover.interval.seconds", "86400"); + props.setProperty("ranger.authz.audit.hdfs.config.destination.open.retry.interval.seconds", "60"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.directory", "/var/log/hbase/audit/%app-type%"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.file", "%time:yyyyMMdd-HHmm.ss%.log"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.file.buffer.size.bytes", "8192"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.flush.interval.seconds", "60"); + props.setProperty("ranger.authz.audit.hdfs.config.local.buffer.rollover.interval.seconds", "600"); + props.setProperty("ranger.authz.audit.hdfs.config.local.archive.directory", "/var/log/hbase/audit/archive/%app-type%"); + props.setProperty("ranger.authz.audit.hdfs.config.local.archive.max.file.count", "10"); + + props.setProperty("ranger.authz.audit.solr.is.async", "true"); + props.setProperty("ranger.authz.audit.solr.async.max.queue.size", "1"); + props.setProperty("ranger.authz.audit.solr.async.max.flush.interval.ms", "1000"); + props.setProperty("ranger.authz.audit.solr.solr_url", "http://localhost:6083/solr/ranger_audits"); + + return props; + } + + private static Properties createAuditV3Properties() { + Properties props = new Properties(); + + props.setProperty("ranger.authz.audit.is.enabled", "true"); + props.setProperty("ranger.authz.audit.destination.hdfs", "false"); + props.setProperty("ranger.authz.audit.destination.solr", "true"); + props.setProperty("ranger.authz.audit.destination.log4j", "false"); + + props.setProperty("ranger.authz.audit.destination.hdfs.dir", "hdfs://namenode:8020/ranger/audit"); + props.setProperty("ranger.authz.audit.destination.hdfs.subdir", "%app-type%/%time:yyyyMMdd%"); + props.setProperty("ranger.authz.audit.destination.hdfs.filename.format", "%app-type%_ranger_audit_%hostname%.log"); + props.setProperty("ranger.authz.audit.destination.hdfs.filewriter.impl", "org.apache.ranger.audit.utils.RangerJSONAuditWriter"); + + props.setProperty("ranger.authz.audit.destination.solr.urls", "http://localhost:6083/solr/ranger_audits"); + props.setProperty("ranger.authz.audit.destination.solr.collection", "ranger_audits"); + + return props; + } + + private static Properties createAllAuthzProperties() { + Properties props = createDefaultProperties(); + + props.putAll(createAuditV2Properties()); + props.putAll(createAuditV3Properties()); + + props.setProperty("ranger.authz.service.hive.service.name", "dev_hive"); + + return props; + } +} diff --git a/authz-embedded/src/test/resources/test_hive/README.txt b/authz-embedded/src/test/resources/test_hive/README.txt new file mode 100644 index 0000000000..6deeab1dba --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/README.txt @@ -0,0 +1,26 @@ +1. Test Setup + 1. database=mydb, table=tbl1, column=* + user=tbl1-r-user, permission=select + user=tbl1-rw-user, permission=select,update + 2. database=mydb, table=tbl2, column=* + user=tbl2-r-user, permission=select + user=tbl2-rw-user, permission=select,update + 3. database=mydb, table=*, column=* + user=all-tbl-r-user, permission=select + 4. database=mydb, table=tbl_tag1, column=* + tag=TAG1 + user=tag1-r-user, permission=select + user=tag1-rw-user, permission=select,update + 5. database=mydb, table=tbl_tag2, column=* + tag=TAG2 + user=tag2-r-user, permission=select + user=tag2-rw-user, permission=select,update + 6. database=mydb, table=tbl_ds1, column=* + dataset=ds1 + user=ds1-r-user, permission=select + 7. database=mydb, table=tbl_ds2, column=* + dataset=ds2 + user=ds2-r-user, permission=select + 8. database=mydb, table=tbl_ds3, column=col1,col2,col3 + dataset=ds3, col1=mask_hash, row-filter=(year=current_year()) + user=ds3-r-user, permission=select diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json new file mode 100644 index 0000000000..975b9dcaac --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive.json @@ -0,0 +1,266 @@ +{ + "serviceId": 5, "serviceName": "dev_hive", "policyVersion": 15, + "policies": [ + { + "id": 1, "name": "mydb.tbl1", "version": 1, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl1" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "tbl1-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tbl1-rw-user" ] } + ] + }, + { + "id": 2, "name": "mydb.tbl2", "version": 1, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl2" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "tbl2-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tbl2-rw-user" ] } + ] + }, + { + "id": 3, "name": "mydb.*.*", "version": 2, + "resources": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "*" ] }, "column": { "values": [ "*" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tbl-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 3, "name": "hive", "displayName": "Hadoop SQL", "label": "Hadoop SQL", "description": "Hadoop SQL", "implClass": "org.apache.ranger.services.hive.RangerServiceHive", "version": 1, + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 3, "name": "udf", "description": "Hive UDF", "label": "Hive UDF", "type": "string", "parent": "database", "level": 20, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 4, "name": "column", "description": "Hive Column", "label": "Hive Column", "type": "string", "parent": "table", "level": 30, + "excludesSupported": true, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 5, "name": "url", "description": "URL", "label": "URL", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": true, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerURLResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + }, + { + "itemId": 6, "name": "hiveservice", "description": "Hive Service", "label": "Hive Service", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + }, + { + "itemId": 7, "name": "global", "description": "Global", "label": "Global", "type": "string", "parent": "", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "true" } + } + ], + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" }, + { "itemId": 2, "name": "update", "label": "update", "category": "UPDATE" }, + { "itemId": 3, "name": "create", "label": "Create", "category": "CREATE" }, + { "itemId": 4, "name": "drop", "label": "Drop", "category": "DELETE" }, + { "itemId": 5, "name": "alter", "label": "Alter", "category": "CREATE" }, + { "itemId": 6, "name": "index", "label": "Index", "category": "MANAGE" }, + { "itemId": 7, "name": "lock", "label": "Lock", "category": "MANAGE" }, + { "itemId": 8, "name": "all", "label": "All", "impliedGrants": [ "select", "update", "create", "drop", "alter", "index", "lock", "read", "write", "repladmin", "serviceadmin", "refresh" ] }, + { "itemId": 9, "name": "read", "label": "Read", "category": "READ" }, + { "itemId": 10, "name": "write", "label": "Write", "category": "UPDATE" }, + { "itemId": 11, "name": "repladmin", "label": "ReplAdmin", "category": "MANAGE" }, + { "itemId": 12, "name": "serviceadmin", "label": "Service Admin", "category": "MANAGE" }, + { "itemId": 13, "name": "tempudfadmin", "label": "Temporary UDF Admin", "category": "MANAGE" }, + { "itemId": 14, "name": "refresh", "label": "Refresh", "category": "MANAGE" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "_expression", "description": "Boolean expression", "label": "Enter boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "username", "label": "Username", "mandatory": true, "type": "string" }, + { "itemId": 2, "name": "password", "label": "Password", "mandatory": true, "type": "password" }, + { "itemId": 3, "name": "jdbc.driverClassName", "label": "jdbc.driverClassName", "mandatory": true, "type": "string", "defaultValue": "org.apache.hive.jdbc.HiveDriver" }, + { "itemId": 4, "name": "jdbc.url", "label": "jdbc.url" , "mandatory": true, "type": "string" }, + { "itemId": 5, "name": "commonNameForCertificate", "label": "Common Name for Certificate", "mandatory": false, "type": "string" }, + { "itemId": 6, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "options": { "enableDenyAndExceptionsInPolicies": "true", "enableTagBasedPolicies": "true" }, + "markerAccessTypes": [ + { "itemId": 101, "label": "_CREATE", "name": "_CREATE", "impliedGrants": [ "create", "alter" ] }, + { "itemId": 102, "label": "_READ", "name": "_READ", "impliedGrants": [ "select", "read" ] }, + { "itemId": 103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "update", "write" ] }, + { "itemId": 104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "drop" ] }, + { "itemId": 105, "label": "_MANAGE", "name": "_MANAGE", "impliedGrants": [ "tempudfadmin", "serviceadmin", "index", "lock", "refresh", "repladmin" ] }, + { "itemId": 106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "drop", "all", "select", "read", "update", "index", "refresh", "tempudfadmin", "serviceadmin", "create", "lock", "repladmin", "write", "alter" ] } + ], + "dataMaskDef": { + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 4, "name": "column", "description": "Hive Column", "label": "Hive Column", "type": "string", "parent": "table", "level": 30, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "maskTypes": [ + { "itemId": 1, "name": "MASK", "label": "Redact", "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'", "transformer": "mask({col})" }, + { "itemId": 2, "name": "MASK_SHOW_LAST_4", "label": "Partial mask: show last 4", "description": "Show last 4 characters; replace rest with 'x'", "transformer": "mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3, "name": "MASK_SHOW_FIRST_4", "label": "Partial mask: show first 4", "description": "Show first 4 characters; replace rest with 'x'", "transformer": "mask_show_first_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 4, "name": "MASK_HASH", "label": "Hash", "description": "Hash the value", "transformer": "mask_hash({col})"}, + { "itemId": 5, "name": "MASK_NULL", "label": "Nullify", "description": "Replace with NULL" }, + { "itemId": 6, "name": "MASK_NONE", "label": "Unmasked (retain original value)", "description": "No masking" }, + { "itemId": 7, "name": "MASK_DATE_SHOW_YEAR", "label": "Date: show only year", "transformer": "mask({col}, 'x', 'x', 'x', -1, '1', 1, 0, -1)", "description": "Date: show only year" }, + { "itemId": 8, "name": "CUSTOM", "label": "Custom", "description": "Custom" } + ] + }, + "rowFilterDef": { + "accessTypes": [ + { "itemId": 1, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "database", "description": "Hive Database", "label": "Hive Database", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": false, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "table", "description": "Hive Table", "label": "Hive Table", "type": "string", "parent": "database", "level": 20, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ] + } + }, + "tagPolicies": { + "serviceId": 3, "serviceName": "dev_tag", "policyVersion": 3, + "policies": [ + { + "id": 11, "name": "TAG1", "version": 1, + "resources": { "tag": { "values": [ "TAG1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tag-r-user", "tag1-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tag1-rw-user" ] } + ] + }, + { + "id": 12, "name": "TAG2", "version": 1, + "resources": { "tag": { "values": [ "TAG2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "select" } ], "users": [ "all-tag-r-user", "tag2-r-user" ] }, + { "accesses": [ { "type": "select" }, { "type": "update" } ], "users": [ "tag2-rw-user" ] } + ] + }, + { + "id": 13, "name": "TAG-X", "version": 1, + "resources": { "tag": { "values": [ "TAG-X" ] } }, + "policyItems": [ + { "accesses": [ { "isAllowed": true, "type": "select" } ], "users": [ "all-tag-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 100, "name": "tag", "displayName": "tag", "label": "TAG", "description": "TAG Service Definition", "implClass": "org.apache.ranger.services.tag.RangerServiceTag", "version": 21, + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "accessTypes": [ + { "itemId": 3001, "name": "select", "label": "select", "category": "READ" }, + { "itemId": 3002, "name": "update", "label": "update", "category": "UPDATE" }, + { "itemId": 3003, "name": "create", "label": "Create", "category": "CREATE" }, + { "itemId": 3004, "name": "drop", "label": "Drop", "category": "DELETE" }, + { "itemId": 3005, "name": "alter", "label": "Alter", "category": "CREATE" }, + { "itemId": 3006, "name": "index", "label": "Index", "category": "MANAGE" }, + { "itemId": 3007, "name": "lock", "label": "Lock", "category": "MANAGE" }, + { "itemId": 3008, "name": "all", "label": "All", "impliedGrants": [ "select", "update", "create", "drop", "alter", "index", "lock", "read", "write", "repladmin", "serviceadmin", "refresh" ] }, + { "itemId": 3009, "name": "read", "label": "Read", "category": "READ" }, + { "itemId": 3010, "name": "write", "label": "Write", "category": "UPDATE" }, + { "itemId": 3011, "name": "repladmin", "label": "ReplAdmin", "category": "MANAGE" }, + { "itemId": 3012, "name": "serviceadmin", "label": "Service Admin", "category": "MANAGE" }, + { "itemId": 3013, "name": "tempudfadmin", "label": "Temporary UDF Admin", "category": "MANAGE" }, + { "itemId": 3014, "name": "refresh", "label": "Refresh", "category": "MANAGE" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "accessed-after-expiry", "label": "Accessed after expiry_date (yes/no)?", "description": "Accessed after expiry_date? (yes/no)", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptTemplateConditionEvaluator", "evaluatorOptions": { "scriptTemplate": "ctx.isAccessedAfter('expiry_date');" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "contextEnrichers": [ + { "itemId": 1, "name": "TagEnricher", "enricher": "org.apache.ranger.plugin.contextenricher.RangerTagEnricher", "enricherOptions": { "tagRetrieverClassName": "org.apache.ranger.plugin.contextenricher.RangerAdminTagRetriever", "tagRefresherPollingInterval": "60000" } } + ], + "markerAccessTypes": [ + { "itemId": 250101, "label": "_CREATE", "name": "_CREATE", "impliedGrants": [ "create", "alter" ] }, + { "itemId": 250102, "label": "_READ", "name": "_READ", "impliedGrants": [ "select", "read" ] }, + { "itemId": 250103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "update", "write" ] }, + { "itemId": 250104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "drop" ] }, + { "itemId": 250105, "label": "_MANAGE", "name": "_MANAGE", "impliedGrants": [ "tempudfadmin", "serviceadmin", "index", "lock", "refresh", "repladmin" ] }, + { "itemId": 250106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "drop", "all", "select", "read", "update", "index", "refresh", "tempudfadmin", "serviceadmin", "create", "lock", "repladmin", "write", "alter" ] } + ], + "dataMaskDef": { + "accessTypes": [ + { "itemId": 3001, "name": "select", "label": "select", "category": "READ" } + ], + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "maskTypes": [ + { "itemId": 3001, "name": "hive:MASK", "label": "Redact", "description": "Replace lowercase with 'x', uppercase with 'X', digits with '0'", "transformer": "mask({col})" }, + { "itemId": 3002, "name": "hive:MASK_SHOW_LAST_4", "label": "Partial mask: show last 4", "description": "Show last 4 characters; replace rest with 'x'", "transformer": "mask_show_last_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3003, "name": "hive:MASK_SHOW_FIRST_4", "label": "Partial mask: show first 4", "description": "Show first 4 characters; replace rest with 'x'", "transformer": "mask_show_first_n({col}, 4, 'x', 'x', 'x', -1, '1')" }, + { "itemId": 3004, "name": "hive:MASK_HASH", "label": "Hash", "description": "Hash the value", "transformer": "mask_hash({col})"}, + { "itemId": 3005, "name": "hive:MASK_NULL", "label": "Nullify", "description": "Replace with NULL" }, + { "itemId": 3006, "name": "hive:MASK_NONE", "label": "Unmasked (retain original value)", "description": "No masking" }, + { "itemId": 3007, "name": "hive:MASK_DATE_SHOW_YEAR", "label": "Date: show only year", "transformer": "mask({col}, 'x', 'x', 'x', -1, '1', 1, 0, -1)", "description": "Date: show only year" }, + { "itemId": 3008, "name": "hive:CUSTOM", "label": "Custom", "description": "Custom" } + ] + } + } + } +} diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json new file mode 100644 index 0000000000..93807ed202 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_gds.json @@ -0,0 +1,112 @@ +{ + "serviceName": "dev_hive", "gdsVersion": 19, + "datasets": [ + { + "id": 1, "name": "ds1", + "policies": [ + { + "id": 41, "name": "DATASET: ds1", "version": 1, + "resources": { "dataset-id": { "values": [ "1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds1-r-user" ] } + ] + } + ] + }, + { + "id": 2, "name": "ds2", + "policies": [ + { + "id": 42, "name": "DATASET: ds2", "version": 1, + "resources": { "dataset-id": { "values": [ "2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds2-r-user" ] } + ] + } + ] + }, + { + "id": 3, "name": "ds3", + "policies": [ + { + "id": 43, "name": "DATASET: ds3", "version": 1, + "resources": { "dataset-id": { "values": [ "3" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds3-r-user" ] } + ] + } + ] + } + ], + "dataShares": [ + { "id": 1, "name": "hive-ds1", "defaultAccessTypes": [ "select" ] }, + { "id": 2, "name": "hive-ds2", "defaultAccessTypes": [ "select" ] }, + { "id": 3, "name": "hive-ds3", "defaultAccessTypes": [ "select" ] } + ], + "dshids": [ + { "dataShareId": 1, "datasetId": 1, "status": "ACTIVE" }, + { "dataShareId": 2, "datasetId": 2, "status": "ACTIVE" }, + { "dataShareId": 3, "datasetId": 3, "status": "ACTIVE" } + ], + "resources": [ + { + "id": 1, "name": "mydb.tbl_ds1", "dataShareId": 1, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds1" ] } } + }, + { + "id": 2, "name": "mydb.tbl_ds2", "dataShareId": 2, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds2" ] } } + }, + { + "id": 3, "name": "mydb.tbl_ds3", "dataShareId": 3, + "resource": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_ds3" ] } }, "subResource": { "values": [ "col1", "col2", "col3" ] }, "subResourceType": "column", + "rowFilter": { "filterExpr": "year = current_year()" }, + "subResourceMasks": [ + { "values": [ "col1" ], "maskInfo": { "dataMaskType": "MASK_HASH" } } + ] + } + ], + "gdsServiceDef": { + "id": 207, "name": "gds", "label": "GDS", "description": "GDS Service Definition", "displayName": "Governed Data Sharing", "implClass": "org.apache.ranger.services.gds.RangerServiceGds", "version": 1, + "resources": [ + { + "itemId": 1, "name": "dataset-id", "label": "Dataset ID", "description": "Dataset ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + }, + { + "itemId": 2, "name": "project-id", "label": "Project ID", "description": "Project ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + } + ], + "accessTypes": [ + { "itemId": 1, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 2, "name": "_READ", "label": "_READ" }, + { "itemId": 3, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 4, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 5, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 6, "name": "_ALL", "label": "_ALL" } + ], + "markerAccessTypes": [ + { "itemId": 7, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 8, "name": "_READ", "label": "_READ" }, + { "itemId": 9, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 10, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 11, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 12, "name": "_ALL", "label": "_ALL" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" } + }, + { + "itemId": 2, "name": "validitySchedule", "label": "Validity schedule", "description": "Validity schedule", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerValidityScheduleConditionEvaluator" + } + ] + } +} diff --git a/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json new file mode 100644 index 0000000000..b634b3d2c5 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/hive_dev_hive_tag.json @@ -0,0 +1,24 @@ +{ + "serviceName":"dev_hive", "tagVersion":2, + "op":"add_or_update", + "tagDefinitions": { + "0": { "name": "TAG-X" }, + "1": { "name": "TAG1" }, + "2": { "name": "TAG2" } + }, + "tags": { + "0": { "type": "TAG-X" }, + "1": { "type": "TAG1" }, + "2": { "type": "TAG2" } + }, + "serviceResources": [ + { "id": 0, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag-x" ] } } }, + { "id": 1, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag1" ] } } }, + { "id": 2, "serviceName": "dev_hive", "resourceElements": { "database": { "values": [ "mydb" ] }, "table": { "values": [ "tbl_tag2" ] } } } + ], + "resourceToTagIds": { + "0": [ "0" ], + "1": [ "1" ], + "2": [ "2" ] + } +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties b/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties new file mode 100644 index 0000000000..de0c8d2d32 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/ranger-embedded-authz.properties @@ -0,0 +1,23 @@ +# 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. + +ranger.authz.init.services=dev_hive + +ranger.authz.service.dev_hive.servicetype=hive + +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +ranger.authz.default.policy.source.embedded_resource.path=/test_hive + +ranger.authz.audit.is.enabled=false diff --git a/authz-embedded/src/test/resources/test_hive/tests_authz.json b/authz-embedded/src/test/resources/test_hive/tests_authz.json new file mode 100644 index 0000000000..1d25ef073d --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/tests_authz.json @@ -0,0 +1,829 @@ +[ + { + "comment": "tests for tbl mydb.tbl1" + }, + { + "request": { + "requestId": "tbl1-r-user select mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user update mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user select,update mydb/tbl1", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select,update mydb/tbl1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-rw-user update mydb/tbl1", + "user": { "name": "tbl1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-rw-user update mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-rw-user select,update mydb/tbl1", + "user": { "name": "tbl1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-rw-user select,update mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user select mydb/tbl1", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select mydb/tbl1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user update mydb/tbl1", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl2" + }, + { + "request": { + "requestId": "tbl2-r-user select mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user update mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-r-user select,update mydb/tbl2", + "user": { "name": "tbl2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-r-user select,update mydb/tbl2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-rw-user update mydb/tbl2", + "user": { "name": "tbl2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-rw-user update mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl2-rw-user select,update mydb/tbl2", + "user": { "name": "tbl2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl2-rw-user select,update mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user select mydb/tbl2", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user select mydb/tbl2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tbl1-r-user update mydb/tbl2", + "user": { "name": "tbl1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tbl1-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl_tag1" + }, + { + "request": { + "requestId": "tag1-r-user select mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user update mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user select,update mydb/tbl_tag1", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select,update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user update mydb/tbl_tag1", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-rw-user update mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user select,update mydb/tbl_tag1", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-rw-user select,update mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user select mydb/tbl_tag1", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user update mydb/tbl_tag1", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_tag1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_tag1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_tag1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_tag1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_tag2" + }, + { + "request": { + "requestId": "tag2-r-user select mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user update mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user select,update mydb/tbl_tag2", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-r-user select,update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user update mydb/tbl_tag2", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-rw-user update mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user select,update mydb/tbl_tag2", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag2-rw-user select,update mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user select mydb/tbl_tag2", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user select mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user update mydb/tbl_tag2", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "tag1-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_tag2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_tag2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_tag2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_tag2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_tag2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_ds1" + }, + { + "request": { + "requestId": "ds1-r-user select mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select mydb/tbl_ds1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user update mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user select,update mydb/tbl_ds1", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select,update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user select mydb/tbl_ds1", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user update mydb/tbl_ds1", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_ds1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_ds1", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_ds1", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds1" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_ds1", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for tbl mydb/tbl_ds2" + }, + { + "request": { + "requestId": "ds2-r-user select mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select mydb/tbl_ds2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user update mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user select,update mydb/tbl_ds2", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "select", "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds2-r-user select,update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user select mydb/tbl_ds2", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user select mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user update mydb/tbl_ds2", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds1-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user select mydb/tbl_ds2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user select mydb/tbl_ds2", + "decision": "ALLOW", + "permissions": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-tbl-r-user update mydb/tbl_ds2", + "user": { "name": "all-tbl-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds2" }, "action": "update", "permissions": [ "update" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "all-tbl-r-user update mydb/tbl_ds2", + "decision": "DENY", + "permissions": { + "update": { "permission": "update", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for tbl mydb/tbl_ds3" + }, + { + "request": { + "requestId": "ds3-r-user select mydb/tbl_ds3", + "user": { "name": "ds3-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds3" }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds3-r-user select mydb/tbl_ds3", + "decision": "DENY", + "permissions": { + "select": { "permission": "select", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds3-r-user select mydb/tbl_ds3 col1,col2,col3", + "user": { "name": "ds3-r-user" }, + "access": { "resource": { "name": "table:mydb/tbl_ds3", "subResources": [ "column:col1", "column:col2", "column:col3" ] }, "action": "select", "permissions": [ "select" ] }, + "context": { "serviceName": "dev_hive" } + }, + "result": { + "requestId": "ds3-r-user select mydb/tbl_ds3 col1,col2,col3", + "decision": "ALLOW", + "permissions": { + "select": { + "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "rowFilter": { "filterExpr": "year = current_year()", "policy": { "id": 43, "version": 1 } }, + "subResources": { + "column:col1": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "dataMask": { "maskType": "MASK_HASH", "policy": { "id": 43, "version": 1 } } }, + "column:col2": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } } }, + "column:col3": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } } } + } + } + } + } + } +] diff --git a/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json b/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json new file mode 100644 index 0000000000..0fee56e664 --- /dev/null +++ b/authz-embedded/src/test/resources/test_hive/tests_resource_permissions.json @@ -0,0 +1,141 @@ +[ + { + "resource": { "name": "table:mydb/tbl1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "tbl1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + }, + "tbl1-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "tbl2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + }, + "tbl2-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_tag1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_tag1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_tag2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_tag2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-rw-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "update": { "permission": "update", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds1-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds2" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds2" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds2-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "table:mydb/tbl_ds3" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "table:mydb/tbl_ds3" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + } + }, + { + "resource": { "name": "column:mydb/tbl_ds3/col1" }, + "context": { "serviceName": "dev_hive" }, + "permissions": { + "resource": { "name": "column:mydb/tbl_ds3/col1" }, + "users": { + "all-tbl-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds3-r-user": { + "select": { "permission": "select", "access": { "decision": "ALLOW", "policy": { "id": 43, "version": 1 } }, "dataMask": null } + } + } + } + } +] diff --git a/authz-embedded/src/test/resources/test_s3/README.txt b/authz-embedded/src/test/resources/test_s3/README.txt new file mode 100644 index 0000000000..fb6e3640d7 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/README.txt @@ -0,0 +1,23 @@ +1. Test Setup + 1. s3a://mybucket/path/path1/* + user=path1-r-user, permission=read + user=path1-rw-user, permission=read,write + 2. s3a://mybucket/path/path2/* + user=path2-r-user, permission=read + user=path2-rw-user, permission=read,write + 3. s3a://mybucket/* + user=all-path-r-user, permission=read + 4. s3a://mybucket/data/tag1/* + tag=TAG1 + user=tag1-r-user, permission=read + user=tag1-rw-user, permission=read,write + 5. s3a://mybucket/data/tag2 + tag=TAG2 + user=tag2-r-user, permission=read + user=tag2-rw-user, permission=read,write + 6. s3a://mybucket/data/ds1 + dataset=ds1 + user=ds1-r-user, permission=read + 7. s3a://mybucket/data/ds2 + dataset=ds2 + user=ds2-r-user, permission=read diff --git a/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties b/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties new file mode 100644 index 0000000000..6f808a6579 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/ranger-embedded-authz.properties @@ -0,0 +1,23 @@ +# 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. + +ranger.authz.init.services=dev_s3 + +ranger.authz.service.dev_s3.servicetype=s3 + +ranger.authz.default.policy.source.impl=org.apache.ranger.admin.client.EmbeddedResourcePolicySource +ranger.authz.default.policy.source.embedded_resource.path=/test_s3 + +ranger.authz.audit.is.enabled=false diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json new file mode 100644 index 0000000000..77ff001729 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3.json @@ -0,0 +1,139 @@ +{ + "serviceId": 1, "serviceName": "dev_s3", "policyVersion": 15, + "policies": [ + { + "id": 1, "name": "mybucket/path/path1", "version": 1, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/path1" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "path1-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "path1-rw-user" ] } + ] + }, + { + "id": 2, "name": "mybucket/path/path2", "version": 1, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/path2" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "path2-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "path2-rw-user" ] } + ] + }, + { + "id": 3, "name": "mybucket/*", "version": 2, + "resources": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "*" ], "isRecursive": true } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-path-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 1, "name": "s3", "displayName": "s3", "label": "AWS S3", "description": "AWS S3", "implClass": "org.apache.ranger.services.s3.RangerServiceS3", "version": 1, + "resources": [ + { + "itemId": 1, "name": "bucket", "description": "S3 Bucket", "label": "S3 Bucket", "type": "string", "level": 10, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + }, + { + "itemId": 2, "name": "path", "description": "HDFS file or directory path", "label": "Resource Path", "type": "path", "parent": "bucket", "level": 20, + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": true, "rrnTemplate": "{bucket}/{path}", + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerPathResourceMatcher", "matcherOptions": { "ignoreCase": "true", "wildCard": "true" } + } + ], + "accessTypes": [ + { "itemId": 1, "name": "read", "label": "Read", "category": "READ"}, + { "itemId": 2, "name": "write", "label": "Write", "category": "UPDATE"}, + { "itemId": 3, "name": "list", "label": "List", "category": "READ"}, + { "itemId": 4, "name": "delete", "label": "Delete", "category": "DELETE"} + ], + "policyConditions": [ + { + "itemId": 1, "name": "_expression", "description": "Boolean expression", "label": "Enter boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "options": { "enableDenyAndExceptionsInPolicies": "true", "enableTagBasedPolicies": "true" }, + "markerAccessTypes": [ + { "itemId": 101, "label": "_CREATE", "name": "_CREATE" }, + { "itemId": 102, "label": "_READ", "name": "_READ", "impliedGrants": [ "read", "list" ] }, + { "itemId": 103, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "write" ] }, + { "itemId": 104, "label": "_DELETE", "name": "_DELETE", "impliedGrants": [ "delete" ] }, + { "itemId": 105, "label": "_MANAGE", "name": "_MANAGE" }, + { "itemId": 106, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "read", "write", "list", "delete" ] } + ] + }, + "tagPolicies": { + "serviceId": 3, "serviceName": "dev_tag", "policyVersion": 3, + "policies": [ + { + "id": 11, "name": "TAG1", "version": 1, + "resources": { "tag": { "values": [ "TAG1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-tag-r-user", "tag1-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "tag1-rw-user" ] } + ] + }, + { + "id": 12, "name": "TAG2", "version": 1, + "resources": { "tag": { "values": [ "TAG2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "read" } ], "users": [ "all-tag-r-user", "tag2-r-user" ] }, + { "accesses": [ { "type": "read" }, { "type": "write" } ], "users": [ "tag2-rw-user" ] } + ] + }, + { + "id": 13, "name": "TAG-X", "version": 1, + "resources": { "tag": { "values": [ "TAG-X" ] } }, + "policyItems": [ + { "accesses": [ { "isAllowed": true, "type": "read" } ], "users": [ "all-tag-r-user" ] } + ] + } + ], + "serviceDef": { + "id": 100, "name": "tag", "displayName": "tag", "label": "TAG", "description": "TAG Service Definition", "implClass": "org.apache.ranger.services.tag.RangerServiceTag", "version": 21, + "resources": [ + { + "itemId": 1, "name": "tag", "label": "TAG", "description": "TAG", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": true, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\":true }" + } + ], + "accessTypes": [ + { "itemId": 1001, "name": "read", "label": "Read", "category": "READ"}, + { "itemId": 1002, "name": "write", "label": "Write", "category": "UPDATE"}, + { "itemId": 1003, "name": "list", "label": "List", "category": "READ"}, + { "itemId": 1004, "name": "delete", "label": "Delete", "category": "DELETE"} + ], + "policyConditions": [ + { + "itemId": 1, "name": "accessed-after-expiry", "label": "Accessed after expiry_date (yes/no)?", "description": "Accessed after expiry_date? (yes/no)", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptTemplateConditionEvaluator", "evaluatorOptions": { "scriptTemplate": "ctx.isAccessedAfter('expiry_date');" }, + "uiHint": "{ \"singleValue\":true }" + }, + { + "itemId": 2, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" }, + "uiHint": "{ \"isMultiline\":true }" + } + ], + "configs": [ + { "itemId": 1, "name": "ranger.plugin.audit.filters", "label": "Ranger Default Audit Filters", "mandatory": false, "type": "string", "defaultValue": "[ {'accessResult': 'DENIED', 'isAudited': true} ]" } + ], + "contextEnrichers": [ + { "itemId": 1, "name": "TagEnricher", "enricher": "org.apache.ranger.plugin.contextenricher.RangerTagEnricher", "enricherOptions": { "tagRetrieverClassName": "org.apache.ranger.plugin.contextenricher.RangerAdminTagRetriever", "tagRefresherPollingInterval": "60000" } } + ], + "markerAccessTypes": [ + { "itemId": 205208, "label": "_CREATE", "name": "_CREATE" }, + { "itemId": 205209, "label": "_READ", "name": "_READ", "impliedGrants": [ "read", "execute" ] }, + { "itemId": 205210, "label": "_UPDATE", "name": "_UPDATE", "impliedGrants": [ "write" ] }, + { "itemId": 205211, "label": "_DELETE", "name": "_DELETE" }, + { "itemId": 205212, "label": "_MANAGE", "name": "_MANAGE" }, + { "itemId": 205213, "label": "_ALL", "name": "_ALL", "impliedGrants": [ "read", "execute", "write" ] } + ] + } + } +} diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json new file mode 100644 index 0000000000..3a474e8b80 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_gds.json @@ -0,0 +1,90 @@ +{ + "serviceName": "dev_s3", "gdsVersion": 19, + "datasets": [ + { + "id": 1, "name": "ds1", + "policies": [ + { + "id": 41, "name": "DATASET: ds1", "version": 1, + "resources": { "dataset-id": { "values": [ "1" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds1-r-user" ] } + ] + } + ] + }, + { + "id": 2, "name": "ds2", + "policies": [ + { + "id": 42, "name": "DATASET: ds2", "version": 1, + "resources": { "dataset-id": { "values": [ "2" ] } }, + "policyItems": [ + { "accesses": [ { "type": "_READ" } ], "users": [ "ds2-r-user" ] } + ] + } + ] + } + ], + "dataShares": [ + { "id": 1, "name": "s3-ds1", "defaultAccessTypes": [ "read" ] }, + { "id": 2, "name": "s3-ds2", "defaultAccessTypes": [ "read" ] } + ], + "dshids": [ + { "dataShareId": 1, "datasetId": 1, "status": "ACTIVE" }, + { "dataShareId": 2, "datasetId": 2, "status": "ACTIVE" } + ], + "resources": [ + { + "id": 1, "name": "mybucket/data/ds1", "dataShareId": 1, + "resource": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/ds1" ], "isRecursive": true } } + }, + { + "id": 2, "name": "mybucket/data/ds2", "dataShareId": 2, + "resource": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/ds2" ], "isRecursive": true } } + } + ], + "gdsServiceDef": { + "id": 207, "name": "gds", "label": "GDS", "description": "GDS Service Definition", "displayName": "Governed Data Sharing", "implClass": "org.apache.ranger.services.gds.RangerServiceGds", "version": 1, + "resources": [ + { + "itemId": 1, "name": "dataset-id", "label": "Dataset ID", "description": "Dataset ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + }, + { + "itemId": 2, "name": "project-id", "label": "Project ID", "description": "Project ID", "level": 1, "type": "string", + "excludesSupported": false, "isValidLeaf": true, "lookupSupported": false, "mandatory": true, "recursiveSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "ignoreCase": "false", "wildCard": "false" }, + "uiHint": "{ \"singleValue\": true }" + } + ], + "accessTypes": [ + { "itemId": 1, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 2, "name": "_READ", "label": "_READ" }, + { "itemId": 3, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 4, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 5, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 6, "name": "_ALL", "label": "_ALL" } + ], + "markerAccessTypes": [ + { "itemId": 7, "name": "_CREATE", "label": "_CREATE" }, + { "itemId": 8, "name": "_READ", "label": "_READ" }, + { "itemId": 9, "name": "_UPDATE", "label": "_UPDATE" }, + { "itemId": 10, "name": "_DELETE", "label": "_DELETE" }, + { "itemId": 11, "name": "_MANAGE", "label": "_MANAGE" }, + { "itemId": 12, "name": "_ALL", "label": "_ALL" } + ], + "policyConditions": [ + { + "itemId": 1, "name": "expression", "label": "Enter boolean expression", "description": "Boolean expression", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerScriptConditionEvaluator", "evaluatorOptions": { "engineName": "JavaScript", "ui.isMultiline": "true" } + }, + { + "itemId": 2, "name": "validitySchedule", "label": "Validity schedule", "description": "Validity schedule", + "evaluator": "org.apache.ranger.plugin.conditionevaluator.RangerValidityScheduleConditionEvaluator" + } + ] + } +} diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json new file mode 100644 index 0000000000..d3f34d625c --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_roles.json @@ -0,0 +1,8 @@ +{ + "serviceName":"dev_s3", + "roleVersion":6, + "rangerRoles":[ + { "id": 1, "name":"tag1-readers", "users": [ { "name": "user1" } ], "groups": [ { "name": "group1" } ], "roles": [ { "name": "role1" } ] }, + { "id": 2, "name":"tag1-updaters", "users": [ { "name": "user11" } ], "groups": [ { "name": "group11" } ], "roles": [ { "name": "role11" } ] } + ] +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json new file mode 100644 index 0000000000..1ed7eb7fb6 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/s3_dev_s3_tag.json @@ -0,0 +1,20 @@ +{ + "serviceName":"dev_s3", "tagVersion":2, + "op":"add_or_update", + "tagDefinitions": { + "1": { "name": "TAG1" }, + "2": { "name": "TAG2" } + }, + "tags": { + "1": { "type": "TAG1" }, + "2": { "type": "TAG2" } + }, + "serviceResources": [ + { "id": 1, "serviceName": "dev_s3", "resourceElements": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/tag1" ], "isRecursive": true } } }, + { "id": 2, "serviceName": "dev_s3", "resourceElements": { "bucket": { "values": [ "mybucket" ] }, "path": { "values": [ "data/tag2" ], "isRecursive": true } } } + ], + "resourceToTagIds": { + "1": [ "1" ], + "2": [ "2" ] + } +} \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_authz.json b/authz-embedded/src/test/resources/test_s3/tests_authz.json new file mode 100644 index 0000000000..aa9da7d63a --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_authz.json @@ -0,0 +1,788 @@ +[ + { + "comment": "tests for path mybucket/data/path1/file.orc" + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user write mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user read,write mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read,write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-rw-user write mybucket/data/path1/file.orc", + "user": { "name": "path1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-rw-user write mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-rw-user read,write mybucket/data/path1/file.orc", + "user": { "name": "path1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-rw-user read,write mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user write mybucket/data/path1/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/path1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/path1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/path1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for path mybucket/data/path2/file.orc" + }, + { + "request": { + "requestId": "path2-r-user read mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user write mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-r-user read,write mybucket/data/path2/file.orc", + "user": { "name": "path2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-r-user read,write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path2-rw-user write mybucket/data/path2/file.orc", + "user": { "name": "path2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-rw-user write mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path2-rw-user read,write mybucket/data/path2/file.orc", + "user": { "name": "path2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path2-rw-user read,write mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path2/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "path1-r-user write mybucket/data/path2/file.orc", + "user": { "name": "path1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/path2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/path2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/path2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/path2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + { + "comment": "tests for path mybucket/data/tag1/file.orc" + }, + { + "request": { + "requestId": "tag1-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user read,write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read,write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-rw-user write mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-rw-user read,write mybucket/data/tag1/file.orc", + "user": { "name": "tag1-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-rw-user read,write mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/tag1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/tag1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/tag1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/tag1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/tag2/file.orc" + }, + { + "request": { + "requestId": "tag2-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-r-user read,write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-r-user read,write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-rw-user write mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag2-rw-user read,write mybucket/data/tag2/file.orc", + "user": { "name": "tag2-rw-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag2-rw-user read,write mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user read mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "tag1-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "tag1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "tag1-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/tag2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/tag2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/tag2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/tag2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/tag2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/ds1/file.orc" + }, + { + "request": { + "requestId": "ds1-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read mybucket/data/ds1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user read,write mybucket/data/ds1/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read,write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/ds1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/ds1/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/ds1/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/ds1/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + + + { + "comment": "tests for path mybucket/data/ds2/file.orc" + }, + { + "request": { + "requestId": "ds2-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read mybucket/data/ds2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds2-r-user read,write mybucket/data/ds2/file.orc", + "user": { "name": "ds2-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "update", "permissions": [ "read", "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds2-r-user read,write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user read mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "read": { "permission": "read", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "ds1-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "ds1-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "ds1-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user read mybucket/data/ds2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "read", "permissions": [ "read" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user read mybucket/data/ds2/file.orc", + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + } + } + }, + { + "request": { + "requestId": "all-path-r-user write mybucket/data/ds2/file.orc", + "user": { "name": "all-path-r-user" }, + "access": { "resource": { "name": "path:mybucket/data/ds2/file.orc" }, "action": "write", "permissions": [ "write" ] }, + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "all-path-r-user write mybucket/data/ds2/file.orc", + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + } +] \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json b/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json new file mode 100644 index 0000000000..407aa733a8 --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_multi_authz.json @@ -0,0 +1,114 @@ +[ + { + "comment": "tests for path1-r-user" + }, + { + "request": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read mybucket/data/path1/file.orc", + "decision": "ALLOW", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user read [mybucket/data/path1/file.orc,mybucket/data/path1/file2.orc]", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + { "resource": { "name": "path:mybucket/data/path1/file2.orc" }, "action": "read", "permissions": [ "read" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user read [mybucket/data/path1/file.orc,mybucket/data/path1/file2.orc]", + "decision": "ALLOW", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + }, + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user [read write] mybucket/data/path1/file.orc", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "read", "permissions": [ "read" ] }, + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user [read write] mybucket/data/path1/file.orc", + "decision": "PARTIAL", + "accesses": [ + { + "decision": "ALLOW", + "permissions": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + }, + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + ] + } + }, + { + "request": { + "requestId": "path1-r-user write [mybucket/data/path1/file.orc,mybucket/data/path2/file.orc]", + "user": { "name": "path1-r-user" }, + "accesses": [ + { "resource": { "name": "path:mybucket/data/path1/file.orc" }, "action": "write", "permissions": [ "write" ] }, + { "resource": { "name": "path:mybucket/data/path2/file.orc" }, "action": "write", "permissions": [ "write" ] } + ], + "context": { "serviceName": "dev_s3" } + }, + "result": { + "requestId": "path1-r-user write [mybucket/data/path1/file.orc,mybucket/data/path2/file.orc]", + "decision": "DENY", + "accesses": [ + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + }, + { + "decision": "DENY", + "permissions": { + "write": { "permission": "write", "access": { "decision": "DENY", "policy": { "id": -1 } } } + } + } + ] + } + } +] \ No newline at end of file diff --git a/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json b/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json new file mode 100644 index 0000000000..a4b458644a --- /dev/null +++ b/authz-embedded/src/test/resources/test_s3/tests_resource_permissions.json @@ -0,0 +1,114 @@ +[ + { + "resource": { "name": "path:mybucket/data/path1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/path1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "path1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + }, + "path1-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 1, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/path2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/path2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "path2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + }, + "path2-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 2, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/tag1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/tag1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + }, + "tag1-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 11, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/tag2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/tag2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "all-tag-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + }, + "tag2-rw-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } }, + "write": { "permission": "write", "access": { "decision": "ALLOW", "policy": { "id": 12, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/ds1/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/ds1/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds1-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 41, "version": 1 } } } + } + } + } + }, + { + "resource": { "name": "path:mybucket/data/ds2/file.orc" }, + "context": { "serviceName": "dev_s3" }, + "permissions": { + "resource": { "name": "path:mybucket/data/ds2/file.orc" }, + "users": { + "all-path-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 3, "version": 2 } } } + }, + "ds2-r-user": { + "read": { "permission": "read", "access": { "decision": "ALLOW", "policy": { "id": 42, "version": 1 } } } + } + } + } + } +] \ No newline at end of file diff --git a/pom.xml b/pom.xml index 40a78ff961..78a2e33966 100755 --- a/pom.xml +++ b/pom.xml @@ -812,6 +812,7 @@ agents-cred agents-installer authz-api + authz-embedded credentialbuilder