Commit d1e9d6e7 authored by Stanley Clark's avatar Stanley Clark
Browse files

Created DB2 policy generator

parent a9890aa4
target
\ No newline at end of file
table|attribute|policy|permission|note
call_center|cc_closed_date_sk||deny|Mask the close date to pretend no call centres were ever closed
catalog_page|cp_catalog_page_number|13 < catalog_page.cp_catalog_page_number|deny|Hide unlucky page number 13
catalog_returns|cr_fee|0 <= catalog_returns.cr_reason_sk|deny|Deny access to the fee when there was a specific reason for returning
catalog_sales|cs_net_profit|0 > catalog_sales.cs_net_profit AND 'sales' = employee.e_role|deny|The company would like to keep their books looking clean and therefore deny access to those cells where there is a negative profit and the person works in sales
customer|c_first_name|customer.c_birth_year = employee.e_year|deny|Deny access if birth year is same as date employee joined the company
customer_demographics|cd_credit_rating|customer.c_birth_country = 'UNITED KINGDOM'|deny|Deny access to credit rating of customers from 'UNITED KINGDOM'
household_demographics|hd_vehicle_count|110000 < income_band.ib_upper_bound AND household_demographics.hd_income_band_sk = income_band.ib_income_band_sk|deny|Mask the vehicle count of customers in an income band with an 'ib_upper_bound > 110000'
income_band|ib_lower_bound|employee.e_role = 'manager'|permit|Deny access to lower income band if not a manager
inventory|inv_quantity_on_hand|warehouse.w_warehouse_sk = inventory.inv_warehouse_sk AND 'United States' = warehouse.w_country|deny|Mask quantities from warehouses in a specific country
item|i_brand_id|1000000 = item.i_brand_id|deny|
reason|r_reason_desc|employee.e_role = 'support'|deny|Deny access to support staff
store_returns|sr_fee|0 <= store_returns.sr_reason_sk|deny|Deny access to the fee when there was a specific reason for returning
store_sales|ss_quantity|13 < store_sales.ss_quantity|deny|store_sales.ss_quantity > 13
web_page|wp_customer_sk||deny|Cells in this column are not allowed to be seen
web_returns|wr_fee|0 <= web_returns.wr_reason_sk|deny|Deny access to the fee when there was a specific reason for returning
web_sales|ws_coupon_amt|1000 < web_sales.ws_net_paid AND 80001 <= income_band.ib_lower_bound AND web_sales.ws_ship_customer_sk = customer.c_customer_sk AND customer.c_current_hdemo_sk = household_demographics.hd_demo_sk AND household_demographics.hd_income_band_sk = income_band.ib_income_band_sk|permit|To protect the privacy of customers who are in a higher income bracket,the value of the coupon used for purchases is only allowed when 'ws_net_paid > 1000' and the customer income band is high ('ib_lower_bound >= 80001')
call_center||employee.e_role = 'sales' OR (date_dim.d_date_sk = call_center.cc_open_date_sk AND 1997 > call_center.cc_open_date_sk)|permit|
catalog_page|||permit|
catalog_returns||(catalog_returns.cr_refunded_customer_sk = customer.c_customer_sk AND customer.c_current_hdemo_sk = household_demographics.hd_demo_sk) AND ((household_demographics.hd_income_band_sk = income_band.ib_income_band_sk AND income_band.ib_lower_bound = 0) OR (household_demographics.hd_buy_potential = '0-500'))|permit|
catalog_sales||(catalog_sales.cs_ship_customer_sk = customer.c_customer_sk AND customer.c_current_hdemo_sk = household_demographics.hd_demo_sk) AND ((household_demographics.hd_income_band_sk = income_band.ib_income_band_sk AND income_band.ib_lower_bound = 0) OR (household_demographics.hd_buy_potential = '0-500'))|permit|Only sales of customers in low income bands or with low buying potential
customer||customer.c_current_addr_sk = customer_address.ca_address_sk AND customer.c_birth_country = customer_address.ca_country|permit|Only customers with an address country the same as their birth country
customer_address||employee.e_role = 'sales' AND 2010 >= employee.e_year|permit|Only employees with role sales who have worked at the company since 2010
customer_demographics|||permit|
date_dim|||permit|
dbgen_version|||deny|
employee|||deny|
household_demographics|||permit|
income_band|||permit|
inventory||inventory.inv_warehouse_sk = warehouse.w_warehouse_sk AND 300000 >= warehouse.w_warehouse_sq_ft|permit|Only inventory for warehouses with small storage space (<= 300000)
item||store_returns.sr_item_sk = item.i_item_sk AND employee.e_store_sk = store_returns.sr_store_sk|permit|Only items which have been returned to the employees own store
promotion||store_sales.ss_promo_sk = promotion.p_promo_sk|permit|Only promotions which are involved in at least one store sale
reason|||permit|
ship_mode|||permit|
store||0 > store.s_closed_date_sk OR 'manager' = employee.e_role|permit|Only stores which are closed or if the employee has role manager
store_returns||store_returns.sr_store_sk = employee.e_store_sk|permit|Only records from employees own store
store_sales||store_sales.ss_store_sk = employee.e_store_sk|permit|Only records from employees own store
time_dim|||permit|
warehouse|||permit|
web_page||0 < web_page.wp_customer_sk|permit|Only web pages with a customer
web_returns||date_dim.d_year > employee.e_year AND web_returns.wr_returned_date_sk = date_dim.d_date_sk|permit|Only returns made after the date the employee joined the company
web_sales||date_dim.d_year > employee.e_year AND web_sales.ws_sold_date_sk = date_dim.d_date_sk|permit|Only sales made after the date the employee joined the company
web_site||web_site.web_country = 'United States'|permit|Only sites in "United States"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stanrogo</groupId>
<artifactId>policy-gen</artifactId>
<version>1.0.0</version>
<!-- Explicitly set desired encoding-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Compile this project using JDK 14 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>14</source>
<target>14</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.util.TablesNamesFinder;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
public class PolicyParser {
public static void main(String[] args) throws IOException, JSQLParserException {
URL loc = PolicyParser.class.getProtectionDomain().getCodeSource().getLocation();
CSVFormat format = CSVFormat.RFC4180.withHeader().withDelimiter('|');
CSVParser parser = new CSVParser(new FileReader(loc.getPath() + "../../policies.csv"), format);
List<String> policies = new ArrayList<>();
for (CSVRecord record : parser) {
String baseTable = record.get("table");
String attribute = record.get("attribute");
String policy = record.get("policy");
String permission = record.get("permission");
String SQL = attribute.isEmpty() ? buildRowPolicy(baseTable, policy, permission) :
buildCellPolicy(baseTable, attribute, policy, permission);
policies.add(SQL);
}
parser.close();
writeSQL(policies);
}
static void writeSQL(List<String> policies) throws IOException {
URL loc = PolicyParser.class.getProtectionDomain().getCodeSource().getLocation();
String fileName = loc.getPath() + "../../../comparison/ibm/sql/policies.sql";
File myObj = new File(fileName);
if ((myObj.delete() && myObj.createNewFile()) || myObj.createNewFile()) {
FileWriter myWriter = new FileWriter(fileName);
myWriter.write(String.join("\n\n", policies));
myWriter.close();
}
}
static String genExists(String baseTable, String policy, String permission)
throws JSQLParserException {
if (policy.isEmpty()) {
String boolPermission = permission.equals("deny") ? "false" : "true";
return "SYSTEM_USER = 'DB2INST1' OR " + boolPermission;
}
Expression stmt = CCJSqlParserUtil.parseCondExpression(policy);
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tableList = tablesNamesFinder.getTableList(stmt);
tableList.removeIf(table -> table.equals(baseTable) || table.equals("employee"));
tableList.add("employee");
String negative = permission.equals("deny") ? "NOT " : "";
return "SYSTEM_USER = 'DB2INST1' OR " +
negative + "EXISTS (SELECT 1 FROM " + String.join(", ", tableList) + " WHERE (" +
policy + ") AND employee.e_name = SYSTEM_USER)";
}
static String buildRowPolicy(String baseTable, String policy, String permission)
throws JSQLParserException {
return "CREATE OR REPLACE PERMISSION " + baseTable + "_ROW_ACCESS ON " + baseTable + " FOR ROWS WHERE\n" +
genExists(baseTable, policy, permission) + "\n" +
"ENFORCED FOR ALL ACCESS ENABLE;\n" +
"ALTER TABLE " + baseTable + " ACTIVATE ROW ACCESS CONTROL;";
}
static String buildCellPolicy(String baseTable, String attribute, String policy,
String permission)
throws JSQLParserException {
return "CREATE OR REPLACE MASK " + attribute + "_COL_MASK ON " + baseTable + " FOR\n" +
"COLUMN " + attribute + " RETURN CASE WHEN (\n" +
genExists(baseTable, policy, permission) + "\n" +
") THEN " + attribute + "\n" +
"ELSE NULL END ENABLE;\n" +
"ALTER TABLE " + baseTable + " ACTIVATE COLUMN ACCESS CONTROL;";
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment