aboutsummaryrefslogtreecommitdiffstats
path: root/dashboard/src/components/policy
diff options
context:
space:
mode:
Diffstat (limited to 'dashboard/src/components/policy')
-rw-r--r--dashboard/src/components/policy/AssignPerimeter.vue244
-rw-r--r--dashboard/src/components/policy/CreateData.vue75
-rw-r--r--dashboard/src/components/policy/CreatePerimeter.vue73
-rw-r--r--dashboard/src/components/policy/CreatePolicy.vue84
-rw-r--r--dashboard/src/components/policy/CreateRule.vue213
-rw-r--r--dashboard/src/components/policy/DataList.vue16
-rw-r--r--dashboard/src/components/policy/FilterRules.vue24
-rw-r--r--dashboard/src/components/policy/Policy.vue186
-rw-r--r--dashboard/src/components/policy/Rule.vue231
-rw-r--r--dashboard/src/components/policy/UnusedData.vue89
10 files changed, 1235 insertions, 0 deletions
diff --git a/dashboard/src/components/policy/AssignPerimeter.vue b/dashboard/src/components/policy/AssignPerimeter.vue
new file mode 100644
index 00000000..07814075
--- /dev/null
+++ b/dashboard/src/components/policy/AssignPerimeter.vue
@@ -0,0 +1,244 @@
+<template>
+ <div >
+ <div v-if="selectedData && loading" class="row padding-10">
+ <h4>Loading...</h4>
+ </div>
+ <div v-if="selectedData && !loading">
+ <div class="p-2">
+ <h3>Assign perimeters to {{ selectedData.name }}</h3>
+ <form-header
+ placeholder="Filter"
+ buttonText="Create Perimeter"
+ @click="creatingPerimeter = true"
+ v-model="filterPerimeter"
+ need-button
+ ></form-header>
+ </div>
+ <create-perimeter
+ v-if="creatingPerimeter"
+ :policy="policy"
+ :type="selectedDataType"
+ @close="creatingPerimeter = false"
+ @perimeterCreated="createPerimeter"
+ ></create-perimeter>
+ <div class="row mt-3" v-else>
+ <div class="col-sm">
+ <h4>
+ All perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.allPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.allPerimeters"></i>
+ </h4>
+ <div class="w-100 height-200 scroll list-group border">
+ <button
+ class="list-group-item"
+ v-for="perimeter in allPerimetersFiltered"
+ :title="perimeter.description"
+ :key="perimeter.id"
+ @click="addPerimeter(perimeter)"
+ >{{ perimeter.name }}</button>
+ </div>
+ <p>Click to add</p>
+ </div>
+ <div class="col-sm">
+ <h4>
+ Policy perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.policyPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.policyPerimeters"></i>
+ </h4>
+ <div class="w-100 height-200 scroll list-group list-group-flush border">
+ <div
+ @click="assign(perimeter)"
+ class="list-group-item"
+ :key="perimeter.id"
+ v-for="perimeter in perimetersFiltered"
+ >
+ <span :title="perimeter.description">{{ perimeter.name }}</span>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click.stop="removePerimeterFromPolicy(perimeter)"
+ title="Remove Perimeter"
+ ></button>
+ </div>
+ </div>
+ <p>Click to assign</p>
+ </div>
+ <div class="col-sm">
+ <h4>
+ Assigned perimeters
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="assignPerimeterHelpStrings.assignedPerimeters" data-toggle="tooltip" :title="assignPerimeterHelpStrings.assignedPerimeters"></i>
+ </h4>
+ <div class="w-100 list-group border height-200 scroll">
+ <button
+ class="list-group-item"
+ :key="perimeter.id"
+ v-for="perimeter in assignmentsFiltered"
+ :title="perimeter.description"
+ @click="unassign(perimeter)"
+ >{{ perimeter.name }}</button>
+ </div>
+ <p>Click to unassign</p>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import util from "./../../services/Util.service.js";
+import FormHeader from "./../FormHeader.vue";
+import CreatePerimeter from "./CreatePerimeter.vue";
+import helpstrings from "../../helpstrings";
+
+var categoryMap = {
+ subject: {
+ perimeterId: "subject_id"
+ },
+ object: {
+ perimeterId: "object_id"
+ },
+ action: {
+ perimeterId: "action_id"
+ }
+};
+
+export default {
+ props: {
+ dataToAssign: Object,
+ policy: Object
+ },
+ components: {
+ FormHeader,
+ CreatePerimeter
+ },
+ data() {
+ return {
+ selectedData: null,
+ selectedDataType: "",
+ loading: false,
+ perimeters: [],
+ allPerimeters: [],
+ assignments: [],
+ filterPerimeter: "",
+ creatingPerimeter: false,
+ assignPerimeterHelpStrings: {}
+ };
+ },
+ mounted() {
+ this.assignPerimeterHelpStrings = helpstrings.assignPerimeter;
+ },
+ computed: {
+ allPerimetersFiltered() {
+ return util.filterAndSortByName(this.allPerimeters, this.filterPerimeter);
+ },
+ perimetersFiltered() {
+ return util.filterAndSortByName(this.perimeters, this.filterPerimeter);
+ },
+ assignmentsFiltered() {
+ return util.filterAndSortByName(this.assignments, this.filterPerimeter);
+ }
+ },
+ watch: {
+ dataToAssign() {
+ this.selectedData = this.dataToAssign.selectedData;
+ this.selectedDataType = this.dataToAssign.selectedDataType;
+ if (this.selectedData) {
+ this.loadPerimeter();
+ }
+ }
+ },
+ methods: {
+ createPerimeter(perimeters) {
+ util.pushAll(this.perimeters, perimeters);
+ },
+ addPerimeter(perimeter) {
+ var self = this;
+ PolicyService.addPerimeterToPolicy(
+ self.selectedDataType,
+ self.policy,
+ perimeter
+ ).then(function() {
+ self.allPerimeters.splice(self.allPerimeters.indexOf(perimeter), 1);
+ self.perimeters.push(perimeter);
+ });
+ },
+ assign(perimeter) {
+ var self = this;
+ PolicyService.createAssignment(
+ self.selectedDataType,
+ self.policy,
+ perimeter,
+ self.selectedData
+ ).then(function() {
+ self.assignments.push(perimeter);
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ });
+ },
+ unassign(perimeter) {
+ var self = this;
+ PolicyService.removeAssignment(
+ self.selectedDataType,
+ self.policy,
+ perimeter,
+ self.selectedData
+ ).then(function() {
+ self.perimeters.push(perimeter);
+ self.assignments.splice(self.assignments.indexOf(perimeter), 1);
+ });
+ },
+ removePerimeterFromPolicy(perimeter) {
+ if (
+ confirm(
+ "Are you sure to delete this Perimeter? (Associated assignments will be deleted too)"
+ )
+ ) {
+ var self = this;
+ PolicyService.removePerimeterFromPolicy(
+ self.selectedDataType,
+ self.policy,
+ perimeter
+ ).then(function() {
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ perimeter.policy_list.splice(
+ perimeter.policy_list.indexOf(self.policy.id),
+ 1
+ );
+ if (perimeter.policy_list.length > 0) {
+ self.allPerimeters.push(perimeter);
+ }
+ });
+ }
+ },
+ loadPerimeter() {
+ var self = this;
+ self.loading = true;
+ self.perimeters = [];
+ self.allPerimeters = [];
+ self.assignments = [];
+
+ PolicyService.loadPerimetersAndAssignments(
+ self.selectedDataType,
+ self.policy
+ ).then(function(values) {
+ var category = categoryMap[self.selectedDataType];
+ self.loading = false;
+ self.perimeters = values.perimeters;
+ var index, perimeter;
+ for (index = 0; index < values.allPerimeters.length; index++) {
+ perimeter = values.allPerimeters[index];
+ if (perimeter.policy_list.indexOf(self.policy.id) < 0) {
+ self.allPerimeters.push(perimeter);
+ }
+ }
+ for (index = 0; index < values.assignments.length; index++) {
+ var assignment = values.assignments[index];
+ if (assignment.assignments.indexOf(self.selectedData.id) >= 0) {
+ perimeter = values.perimetersMap[assignment[category.perimeterId]];
+ self.assignments.push(perimeter);
+ self.perimeters.splice(self.perimeters.indexOf(perimeter), 1);
+ }
+ }
+ });
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/CreateData.vue b/dashboard/src/components/policy/CreateData.vue
new file mode 100644
index 00000000..ca3c5183
--- /dev/null
+++ b/dashboard/src/components/policy/CreateData.vue
@@ -0,0 +1,75 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="dataName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="dataCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="dataName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="dataDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="dataCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createData()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+export default {
+ name: "createData",
+ props: {
+ policy: Object,
+ type: String,
+ category: Object,
+ },
+ data: function() {
+ return {
+ dataCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createData() {
+ var self = this;
+ PolicyService.createData(
+ this.type,
+ this.policy,
+ this.category.id,
+ this.dataCreate
+ ).then(function(datas) {
+ self.$emit("dataCreated", datas[0]);
+ self.close();
+ });
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreatePerimeter.vue b/dashboard/src/components/policy/CreatePerimeter.vue
new file mode 100644
index 00000000..b8a9d532
--- /dev/null
+++ b/dashboard/src/components/policy/CreatePerimeter.vue
@@ -0,0 +1,73 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="perimeterName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="perimeterCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="perimeterName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="perimeterDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="perimeterCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createPerimeter()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+export default {
+ name: "createPerimeter",
+ props: {
+ policy: Object,
+ type: String
+ },
+ data: function() {
+ return {
+ perimeterCreate: {
+ name: "",
+ description: ""
+ }
+ };
+ },
+ methods: {
+ createPerimeter() {
+ var self = this;
+ PolicyService.createPerimeter(
+ this.type,
+ this.policy,
+ this.perimeterCreate
+ ).then(function(perimeters) {
+ self.$emit("perimeterCreated", perimeters);
+ self.close();
+ });
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreatePolicy.vue b/dashboard/src/components/policy/CreatePolicy.vue
new file mode 100644
index 00000000..b3e90c2d
--- /dev/null
+++ b/dashboard/src/components/policy/CreatePolicy.vue
@@ -0,0 +1,84 @@
+<template>
+ <div class="list-group-item row">
+ <form>
+ <div class="form-group">
+ <label for="policyName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="policyCreate.name"
+ v-validate.initial="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="policyName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="policyDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="policyCreate.description"
+ v-validate.initial="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="policyGenre">Genre</label>
+ <select v-model="policyCreate.genre" class="form-control" id="policyGenre" v-validate.initial="'required'" name="genre">
+ <option>admin</option>
+ <option>authz</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="policyModel">Model</label>
+ <select v-model="policyCreate.model_id" class="form-control" id="policyModel" v-validate.initial="'required'" name="model">
+ <option v-for="model in models" :key="model.id" :value="model.id">{{ model.name }}</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createPolicy()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import ModelService from "./../../services/Model.service.js";
+import util from "./../../services/Util.service.js";
+
+export default {
+ name: "createPolicy",
+ data: function() {
+ return {
+ policyCreate: {
+ name: "",
+ description: "",
+ genre: "",
+ model_id: ""
+ }
+ };
+ },
+ computed: {
+ models() {
+ return util.sortByName(ModelService.models);
+ }
+ },
+ methods: {
+ createPolicy() {
+ PolicyService.createPolicy(this.policyCreate);
+ this.close();
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/CreateRule.vue b/dashboard/src/components/policy/CreateRule.vue
new file mode 100644
index 00000000..656fa39a
--- /dev/null
+++ b/dashboard/src/components/policy/CreateRule.vue
@@ -0,0 +1,213 @@
+<template>
+ <div class="list-group-item row">
+ <form v-if="!metaruleId">
+ <div class="form-group">
+ <label for="metarule">Select a Metarule:</label>
+ <select v-model="metaruleId" class="form-control" id="metarule" name="metarule">
+ <option
+ v-for="metarule in policy.model.meta_rules"
+ :key="metarule.id"
+ :value="metarule.id"
+ >{{ metarule.name }}</option>
+ </select>
+ </div>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ </form>
+ <form v-else>
+ <div
+ class="form-group"
+ v-for="(categoryWrapper, index) in ruleData"
+ :key="categoryWrapper.id"
+ >
+ <label
+ :for="categoryWrapper.category.name"
+ >{{ 'Select ' + categoryWrapper.type + ' data of ' + categoryWrapper.category.name + ' category' }}</label>
+ <select
+ v-model="ruleCreate.rule[index]"
+ class="form-control"
+ :id="categoryWrapper.category.name"
+ :name="categoryWrapper.category.name"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="data in categoryWrapper.data"
+ :key="data.id"
+ :value="data.id"
+ >{{ data.name }}</option>
+ </select>
+ <create-data
+ class="m-3"
+ @close="creatingDataCategory = null"
+ @dataCreated="dataCreated(categoryWrapper, $event, index)"
+ :policy="policy"
+ :type="categoryWrapper.type"
+ :category="categoryWrapper.category"
+ v-if="creatingDataCategory == categoryWrapper.category"
+ ></create-data>
+ <button
+ v-else
+ type="button"
+ class="btn btn-primary mt-3"
+ @click="creatingDataCategory = categoryWrapper.category"
+ >Or Create one</button>
+ </div>
+ <div v-for='(attribute, index) in policy.attributes' :key="attribute.id" class="form-group">
+ <label for="ruleAttributes">Attribute {{attribute.id}}</label>
+ <select
+ v-model="attributes[index]"
+ class="form-control"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="value in attribute.values"
+ :key="value"
+ :value="value"
+ >{{ value }}</option>
+ </select>
+ </div>
+ <div class="form-group">
+ <label for="ruleInstructions">Instructions</label>
+ <select
+ v-model="ruleCreate.instructions"
+ class="form-control"
+ v-validate.initial="'required'"
+ >
+ <option
+ v-for="data in instructions"
+ :key="data"
+ :value="data"
+ >{{ data }}</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="close()">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="createRule()"
+ >Create</button>
+ </form>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+import ModelService from "./../../services/Model.service.js";
+import CreateData from "./CreateData.vue";
+
+function addCategories(type, categories, data, mapArray, initArray) {
+ var dataFiltered = [];
+
+ for (var i = 0; i < categories.length; i++) {
+ var category = categories[i];
+ for (var j = 0; j < data.length; j++) {
+ var element = data[j];
+ if (element.category_id == category.id) {
+ dataFiltered.push(element);
+ }
+ }
+
+ mapArray.push({
+ id: category.id,
+ category: category,
+ data: dataFiltered,
+ type: type
+ });
+ initArray.push(dataFiltered.length > 0 ? dataFiltered[0].id : null);
+ }
+}
+
+
+export default {
+ name: "createRule",
+ props: {
+ policy: Object
+ },
+ components: {
+ CreateData
+ },
+ data: function() {
+ return {
+ metarule: null,
+ metaruleId: null,
+ creatingDataCategory: null,
+ ruleData: [],
+ ruleCreate: {
+ instructions: 'grant',
+ rule: [],
+ },
+ instructions: ['grant', 'deny'],
+ attributes: [],
+ attribute: '',
+ };
+ },
+ watch: {
+ policy() {
+ if (this.policy) {
+ this.metaruleId = null;
+ if (this.policy.model.meta_rules.length == 1) {
+ this.metaruleId = this.policy.model.meta_rules[0].id;
+ }
+ }
+ },
+ metaruleId() {
+ if (this.metaruleId) {
+ this.metarule = ModelService.getMetaRule(this.metaruleId);
+ if (this.metarule){
+ for (let i = 0; i < this.policy.attributes.length; i++){
+ let attrs = this.policy.attributes[i].default;
+ this.attributes.push(attrs);
+ }
+ }
+ addCategories(
+ "subject",
+ this.metarule.subject_categories,
+ this.policy.subjectData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ addCategories(
+ "object",
+ this.metarule.object_categories,
+ this.policy.objectData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ addCategories(
+ "action",
+ this.metarule.action_categories,
+ this.policy.actionData,
+ this.ruleData,
+ this.ruleCreate.rule
+ );
+ }
+ }
+ },
+ methods: {
+ createRule() {
+ this.ruleCreate.enabled = true;
+ const instruction = "[{\n\t\"decision\": " + "\"" + this.ruleCreate.instructions + "\"" + "\n}]";
+ this.ruleCreate.instructions = JSON.parse(instruction);
+ this.ruleCreate.meta_rule_id = this.metarule.id;
+ this.ruleCreate.policy_id = this.policy.id;
+ for (let i = 0; i < this.attributes.length; i++) {
+ this.ruleCreate.rule.push("attributes:" + this.attributes[i]);
+ }
+
+ PolicyService.addRuleToPolicy(this.policy, this.ruleCreate);
+ this.close();
+ },
+ dataCreated(wrapper, data, index) {
+ wrapper.data.push(data);
+ this.$set(this.ruleCreate.rule, index, data.id);
+ },
+ close() {
+ this.$emit("close");
+ }
+ }
+};
+</script>
diff --git a/dashboard/src/components/policy/DataList.vue b/dashboard/src/components/policy/DataList.vue
new file mode 100644
index 00000000..40f384f3
--- /dev/null
+++ b/dashboard/src/components/policy/DataList.vue
@@ -0,0 +1,16 @@
+<template>
+ <span>
+ <span v-for="(data, index) in list" :key="data.id">
+ <span v-if="index > 0">,</span>
+ <span>{{ data.name }}</span>
+ </span>
+ </span>
+</template>
+
+<script>
+export default {
+ props: {
+ list: Array
+ }
+}
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/FilterRules.vue b/dashboard/src/components/policy/FilterRules.vue
new file mode 100644
index 00000000..5d685952
--- /dev/null
+++ b/dashboard/src/components/policy/FilterRules.vue
@@ -0,0 +1,24 @@
+<template>
+ <div class="form-inline">
+ <input
+ type="search"
+ class="form-control filter col mr-auto"
+ placeholder="Filter rules"
+ v-bind:value="value"
+ v-on:input="$emit('input', $event.target.value)"
+ >
+ </div>
+</template>
+
+<script>
+ export default {
+ name: "FilterRules",
+ props: {
+ value: String
+ }
+ }
+</script>
+
+<style scoped>
+
+</style> \ No newline at end of file
diff --git a/dashboard/src/components/policy/Policy.vue b/dashboard/src/components/policy/Policy.vue
new file mode 100644
index 00000000..415f6b02
--- /dev/null
+++ b/dashboard/src/components/policy/Policy.vue
@@ -0,0 +1,186 @@
+<template>
+ <div>
+ <template v-if="edit">
+ <form>
+ <div class="form-group" >
+ <label for="policyName">Name</label>
+ <input
+ type="text"
+ name="name"
+ v-model="policyEdit.name"
+ v-validate="'alpha_dash|required|min:3'"
+ class="form-control"
+ id="policyName"
+ />
+ </div>
+ <div class="form-group">
+ <label for="policyDescription">Description</label>
+ <textarea
+ name="description"
+ v-model="policyEdit.description"
+ v-validate="'required|min:3'"
+ class="form-control"
+ ></textarea>
+ </div>
+ <div class="form-group">
+ <label for="policyGenre">Genre</label>
+ <select
+ v-model="policyEdit.genre"
+ class="form-control"
+ id="policyGenre"
+ v-validate.initial="'required'"
+ name="genre"
+ >
+ <option>admin</option>
+ <option>authz</option>
+ </select>
+ </div>
+ <ul>
+ <li v-for="error in errors.all()" :key="error.id">{{ error }}</li>
+ </ul>
+ <button type="button" class="btn btn-secondary" @click="edit = false">Cancel</button>
+ <span>&nbsp;</span>
+ <button
+ type="button"
+ :disabled="errors.any()"
+ class="btn btn-primary"
+ @click="updatePolicy()"
+ >Update</button>
+ </form>
+ </template>
+ <template v-else>
+ <h3 class="list-group-item-heading inline " >{{ policy.name }}</h3>
+ <div class="pull-right">
+ <button
+ type="button"
+ class="fa fa-trash btn-dark btn-sm"
+ title="Remove Policy"
+ @click="removePolicy()"
+ ></button>
+ <button
+ type="button"
+ class="fa fa-edit btn-dark btn-sm"
+ title="Edit Policy"
+ @click="updatingPolicy()"
+ ></button>
+ </div>
+ <p class="list-group-item-text">{{ policy.description }}</p>
+
+ <unused-data :policy="policy" v-if="showAlert" @close="allowAlert = false"></unused-data>
+
+ <details class="list-group-item-text">
+ <summary @click="populatePolicy()">
+ <h4 class="inline-block width-200">
+ Rules
+ <i class="fa fa-question-circle" style="margin-left: 2%" v-if="policyHelpStrings.rules" data-toggle="tooltip" :title="policyHelpStrings.rules"></i>
+ </h4>
+ <button
+ type="button"
+ class="fa fa-plus btn-dark btn-sm"
+ @click="creatingRule = true"
+ title="Add Rule"
+ ></button>
+ </summary>
+ <create-rule v-if="creatingRule" @close="creatingRule = false" :policy="policy"></create-rule>
+ <div class="list-group" v-else>
+ <filter-rules v-model="filter" ></filter-rules>
+ <br/>
+ <p v-if="!policy.rulesPopulated" class="list-group-item-text">Loading rules...</p>
+ <div v-else>
+ <rule
+ v-for="rule in filteredRules"
+ :key="rule.id"
+ :rule="rule"
+ :selected="selectedRule == rule"
+ :policy="policy"
+ @show="selectRule($event)"
+ ></rule>
+ </div>
+ </div>
+ </details>
+ </template>
+ <hr />
+ </div>
+</template>
+
+<script>
+import UnusedData from "./UnusedData.vue";
+import PolicyService from "./../../services/Policy.service.js";
+import util from "./../../services/Util.service.js";
+import Rule from "./Rule.vue";
+import CreateRule from "./CreateRule.vue";
+import FilterRules from "./FilterRules.vue";
+
+import Vue from "vue";
+import helpstrings from "../../helpstrings";
+
+var selectedRule = new Vue({data: {rule: null}});
+
+export default {
+ props: {
+ policy: Object
+ },
+ data() {
+ return {
+ filter: "",
+ edit: false,
+ creatingRule: false,
+ allowAlert: true,
+ policyEdit: {},
+ policyHelpStrings: {}
+ };
+ },
+ mounted() {
+ this.policyHelpStrings = helpstrings.policy;
+ },
+ computed: {
+ filteredRules() {
+ let filteredRules = PolicyService.filterByRules(this.policy.rules, this.filter);
+
+
+ return filteredRules;
+ },
+ selectedRule() {
+ return selectedRule.rule;
+ },
+ showAlert() {
+ return (
+ this.allowAlert &&
+ (this.policy.unusedSubjectData.length ||
+ this.policy.unusedObjectData.length ||
+ this.policy.unusedActionData.length)
+ );
+ },
+ },
+ components: {
+ UnusedData,
+ Rule,
+ CreateRule,
+ FilterRules
+ },
+ methods: {
+ populatePolicy() {
+ PolicyService.populatePolicy(this.policy);
+ },
+ removePolicy() {
+ if (
+ confirm(
+ "Are you sure to delete this Policy? (Associated perimeter, data an PDP will be deleted too)"
+ )
+ )
+ PolicyService.removePolicy(this.policy);
+ },
+ updatingPolicy() {
+ this.policyEdit = util.clone(this.policy);
+ this.edit = true;
+ },
+ updatePolicy() {
+ this.edit = false;
+ PolicyService.updatePolicy(this.policyEdit);
+ },
+ selectRule(rule) {
+ selectedRule.rule = rule;
+ }
+ }
+};
+</script> \ No newline at end of file
diff --git a/dashboard/src/components/policy/Rule.vue b/dashboard/src/components/policy/Rule.vue
new file mode 100644
index 00000000..c8889b86
--- /dev/null
+++ b/dashboard/src/components/policy/Rule.vue
@@ -0,0 +1,231 @@
+<template>
+ <div class="list-group-item">
+ <details >
+ <summary class="list-group-item-heading" :style="ruleIsGrant ? 'background-color: var(--green)' : 'background-color: Tomato'" >
+
+ <b>Rule: </b>
+ <data-list :list="rule.subjectData"></data-list> |
+ <data-list :list="rule.actionData"></data-list> |
+ <data-list :list="rule.objectData"></data-list>
+ <span v-if="rule.attributeData.length"> | <data-list :list="rule.attributeData"></data-list></span>
+ <div class="pull-right" style="background-color: white">
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeRuleFromPolicy()"
+ title="Remove Rule"
+ ></button>
+ <button type="button"
+ :class="ruleIsGrant ? buttonRuleIsGrant : buttonRuleIsDeny"
+ @click="changeRuleDecision()"
+ title="Change Decision"
+ ></button>
+ </div>
+ </summary>
+ <div >
+ <p class="list-group-item-text"></p>
+ <table class="table">
+ <thead>
+ <tr>
+ <th>
+ <span>
+ Subjects data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.subjectsData" data-toggle="tooltip" :title="ruleHelpStrings.subjectsData"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Objects data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.objectsData" data-toggle="tooltip" :title="ruleHelpStrings.objectsData"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Actions data
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.actionsData" data-toggle="tooltip" :title="ruleHelpStrings.actionsData"></i>
+ </span>
+ </th>
+ <th v-if="rule.attributeData.length">
+ <span>
+ Attributes
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.attributes" data-toggle="tooltip" :title="ruleHelpStrings.attributes"></i>
+ </span>
+ </th>
+ <th>
+ <span>
+ Instructions
+ <i class="fa fa-question-circle" v-if="ruleHelpStrings.instructions" data-toggle="tooltip" :title="ruleHelpStrings.instructions"></i>
+ </span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p
+ v-for="data in rule.subjectData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('subject', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td>
+ <p
+ v-for="data in rule.objectData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('object', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td>
+ <p
+ v-for="data in rule.actionData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{ data.name }}</span>
+ <button
+ v-if="selectedData != data"
+ type="button"
+ class="fa fa-exchange pull-right btn-dark btn-sm"
+ @click="assignData('action', data)"
+ title="Assign to perimeters"
+ ></button>
+ <button
+ v-if="selectedData == data"
+ type="button"
+ class="fa fa-times pull-right btn-dark btn-sm"
+ @click="unassignData()"
+ title="Close"
+ ></button>
+ </p>
+ </td>
+ <td v-if="rule.attributeData.length">
+ <p
+ v-for="data in rule.attributeData"
+ :key="data.id"
+ :class="{'selected-data': selectedData == data}"
+ >
+ <span :title="data.description">{{data.id}} : {{ data.name }}</span>
+ </p>
+ </td>
+ <td>
+ <pre><code>{{rule.instructions}}</code></pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <assign-perimeter :policy="policy" :dataToAssign="dataToAssign"></assign-perimeter>
+
+ </div>
+ </details>
+ </div>
+</template>
+
+<script>
+ import AttributeService from "./../../services/Attribute.service"
+ import PolicyService from "./../../services/Policy.service.js";
+ import DataList from "./DataList.vue";
+ import AssignPerimeter from "./AssignPerimeter.vue";
+ import helpstrings from "../../helpstrings";
+
+ export default {
+ props: {
+ rule: Object,
+ selected: Boolean,
+ policy: Object
+ },
+ data() {
+ return {
+ dataToAssign: {
+ selectedData: null,
+ selectedDataType: "",
+ },
+ selectedData: null,
+ ruleIsGrant: false,
+ buttonRuleIsGrant: 'fa fa-toggle-on pull-right btn-dark btn-sm',
+ buttonRuleIsDeny: 'fa fa-toggle-off pull-right btn-dark btn-sm',
+ ruleHelpStrings: {}
+
+ }
+ },
+ components: {
+ DataList,
+ AssignPerimeter,
+ },
+ created() {
+ AttributeService.initialize();
+ },
+ mounted() {
+ this.ruleIsGrant = ("grant".localeCompare(this.rule.instructions[0].decision) == 0);
+ this.ruleHelpStrings = helpstrings.rule;
+ },
+ watch: {
+ selected() {
+ if (!this.selected)
+ this.unassignData();
+ }
+ },
+ methods: {
+ changeRuleDecision() {
+ var decision = ("grant".localeCompare(this.rule.instructions[0].decision) == 0) ? "deny" : "grant";
+ PolicyService.updateRule(this.policy, this.rule, decision).then(res => {
+ this.ruleIsGrant = !this.ruleIsGrant;
+ this.rule.instructions = res;
+ });
+
+ },
+ showRule() {
+ this.$emit("show", this.selected ? null : this.rule);
+ },
+ removeRuleFromPolicy() {
+ if (confirm("Are you sure to delete this Rule?"))
+ PolicyService.removeRuleFromPolicy(this.policy, this.rule);
+ },
+ assignData(type, data) {
+ this.dataToAssign = {
+ selectedData: data,
+ selectedDataType: type,
+ };
+ this.selectedData = data;
+ },
+ unassignData() {
+ this.assignData("", null);
+ }
+ }
+ };
+</script>
+
+<style scoped>
+
+</style> \ No newline at end of file
diff --git a/dashboard/src/components/policy/UnusedData.vue b/dashboard/src/components/policy/UnusedData.vue
new file mode 100644
index 00000000..48b8b642
--- /dev/null
+++ b/dashboard/src/components/policy/UnusedData.vue
@@ -0,0 +1,89 @@
+<template>
+ <div>
+ <div
+ v-if="policy.unusedSubjectData.length
+ || policy.unusedObjectData.length
+ || policy.unusedActionData.length"
+ class="alert alert-dismissable alert-warning"
+ >
+ <button type="button" class="close" data-dismiss="alert" @click="showUnused = false; $emit('close')">×</button>
+ <h4>Warning!</h4>
+ <p>
+ Some data are unused, please check them and delete them if necessary.
+ <a
+ href
+ @click.prevent="showUnused = true"
+ v-show="!showUnused"
+ >Show unused data</a>
+ <a href @click.prevent="showUnused = false" v-show="showUnused">Hide unused data</a>
+ </p>
+ </div>
+
+ <div v-if="showUnused" class="row overflow-hidden mb-3">
+ <div class="list-group col" v-if="policy.unusedSubjectData.length">
+ <h3 class="list-group-item active">Unused Subject data</h3>
+ <div v-for="subject in policy.unusedSubjectData" :key="subject.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="subject.description">{{ subject.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('subject', policy, subject)"
+ title="Remove Subject data"
+ ></button>
+ </div>
+ </div>
+
+ <div class="list-group col" v-if="policy.unusedObjectData.length">
+ <h3 class="list-group-item active">Unused Object data</h3>
+ <div v-for="object in policy.unusedObjectData" :key="object.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="object.description">{{ object.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('object', policy, object)"
+ title="Remove Object data"
+ ></button>
+ </div>
+ </div>
+
+ <div class="list-group col" v-if="policy.unusedActionData.length">
+ <h3 class="list-group-item active">Unused Action data</h3>
+ <div v-for="action in policy.unusedActionData" :key="action.id" class="list-group-item">
+ <h4 class="list-group-item-heading inline" :title="action.description">{{ action.name }}</h4>
+ <button
+ type="button"
+ class="fa fa-trash pull-right btn-dark btn-sm"
+ @click="removeData('action', policy, action)"
+ title="Remove Action data"
+ ></button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import PolicyService from "./../../services/Policy.service.js";
+
+
+export default {
+ props: {
+ policy: Object
+ },
+ data() {
+ return {
+ showUnused: false
+ };
+ },
+ methods: {
+ removeData(type, policy, data) {
+ if (
+ confirm(
+ "Are you sure to delete this Data? (Associated assignments and rules will be deleted too)"
+ )
+ )
+ PolicyService.removeData(type, policy, data);
+ }
+ }
+};
+</script> \ No newline at end of file