diff options
Diffstat (limited to 'dashboard/src/components/policy')
-rw-r--r-- | dashboard/src/components/policy/AssignPerimeter.vue | 244 | ||||
-rw-r--r-- | dashboard/src/components/policy/CreateData.vue | 75 | ||||
-rw-r--r-- | dashboard/src/components/policy/CreatePerimeter.vue | 73 | ||||
-rw-r--r-- | dashboard/src/components/policy/CreatePolicy.vue | 84 | ||||
-rw-r--r-- | dashboard/src/components/policy/CreateRule.vue | 213 | ||||
-rw-r--r-- | dashboard/src/components/policy/DataList.vue | 16 | ||||
-rw-r--r-- | dashboard/src/components/policy/FilterRules.vue | 24 | ||||
-rw-r--r-- | dashboard/src/components/policy/Policy.vue | 186 | ||||
-rw-r--r-- | dashboard/src/components/policy/Rule.vue | 231 | ||||
-rw-r--r-- | dashboard/src/components/policy/UnusedData.vue | 89 |
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> </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> </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> </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> </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> </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 |