aboutsummaryrefslogtreecommitdiffstats
path: root/moon_dashboard/moon/static/moon/policy
diff options
context:
space:
mode:
Diffstat (limited to 'moon_dashboard/moon/static/moon/policy')
-rw-r--r--moon_dashboard/moon/static/moon/policy/policy.controller.js295
-rw-r--r--moon_dashboard/moon/static/moon/policy/policy.html158
-rwxr-xr-xmoon_dashboard/moon/static/moon/policy/policy.service.js330
-rwxr-xr-xmoon_dashboard/moon/static/moon/policy/policy.service.spec.js336
4 files changed, 1119 insertions, 0 deletions
diff --git a/moon_dashboard/moon/static/moon/policy/policy.controller.js b/moon_dashboard/moon/static/moon/policy/policy.controller.js
new file mode 100644
index 00000000..6c6631cf
--- /dev/null
+++ b/moon_dashboard/moon/static/moon/policy/policy.controller.js
@@ -0,0 +1,295 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('moon.policy.controller',
+ controller);
+
+ controller.$inject = ['moon.util.service', 'moon.policy.service', 'moon.model.service', 'horizon.framework.widgets.form.ModalFormService'];
+
+ function controller(util, policyService, modelService, ModalFormService) {
+ var self = this;
+ var genres = [{ value: 'admin', name: gettext('admin') }, { value: 'authz', name: gettext('authz') }];
+ self.model = policyService;
+ self.selectedRule = null;
+ self.currentData = null;
+ policyService.initialize();
+
+ var dataTitleMaps = {};
+
+ var categoryMap = {
+ subject: {
+ perimeterId: 'subject_id'
+ },
+ object: {
+ perimeterId: 'object_id'
+ },
+ action: {
+ perimeterId: 'action_id'
+ },
+ }
+
+ function createAddDataButton(type, index, category, config, policy) {
+ config.form.push({
+ "key": type + index + "Button",
+ "type": "button",
+ "title": "Add",
+ onClick: createDataFunction(type, category, policy)
+ })
+ }
+
+ function createDataFunction(type, category, policy) {
+ return function () {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ }
+ };
+ var data = { name: '', description: '' };
+ var config = {
+ title: gettext('Create Data of ' + category.name + ' category'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: data
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createData(type, policy, category, form.model).then(
+ function (data) {
+ util.pushAll(dataTitleMaps[category.id], util.arrayToTitleMap(data));
+ }
+ );
+ }
+ }
+ }
+
+ function getOrCreateDataTitleMap(category, data, policy) {
+ var result = dataTitleMaps[category.id];
+ if (!result) {
+ result = util.arrayToTitleMap(data);
+ dataTitleMaps[category.id] = result;
+ }
+ return result;
+ }
+
+ function createDataSelect(type, categories, data, config, policy) {
+ for (var i = 0; i < categories.length; i++) {
+ var category = categories[i];
+ var titleMap = getOrCreateDataTitleMap(category, data, policy);
+ config.schema.properties[type + i] = { type: "string", title: gettext('Select ' + type + ' data of ' + category.name + ' category') };
+ config.form.push({ key: type + i, type: 'select', titleMap: titleMap });
+ createAddDataButton(type, i, category, config, policy);
+ }
+ }
+
+ function pushData(type, model, array) {
+ var i = 0;
+ while ((type + i) in model) {
+ array.push(model[type + i]);
+ i++;
+ }
+ }
+
+ self.createPolicy = function createPolicy() {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ genre: { type: "string", title: gettext("genre") },
+ model_id: { type: "string", title: gettext("Select a Model:") }
+ }
+ };
+ var policy = { name: '', description: '', model_id: null, genre: '' };
+ var titleMap = util.arrayToTitleMap(modelService.models)
+ var config = {
+ title: gettext('Create Policy'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }, { key: 'genre', type: 'select', titleMap: genres }, { key: 'model_id', type: 'select', titleMap: titleMap }],
+ model: policy
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createPolicy(form.model);
+ }
+ }
+
+ self.updatePolicy = function updatePolicy(policy) {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ genre: { type: "string", title: gettext("Genre") },
+ }
+ };
+ var config = {
+ title: gettext('Update Policy'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }, { key: 'genre', type: 'select', titleMap: genres }],
+ model: { name: policy.name, description: policy.description, model_id: policy.model_id, id: policy.id, genre: policy.genre }
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.updatePolicy(form.model);
+ }
+ }
+
+ self.addRuleWithMetaRule = function addRuleWithMetaRule(policy, metaRule) {
+ var schema = {
+ type: "object",
+ properties: {
+ instructions: { type: "string", title: gettext("Instructions") }
+ }
+ };
+
+ var config = {
+ title: gettext('Add Rule'),
+ schema: schema,
+ form: [],
+ model: {
+ instructions: '[{"decision": "grant"}]'
+ }
+ };
+ dataTitleMaps = {};
+ createDataSelect('subject', metaRule.subject_categories, policy.subjectData, config, policy);
+ createDataSelect('object', metaRule.object_categories, policy.objectData, config, policy);
+ createDataSelect('action', metaRule.action_categories, policy.actionData, config, policy);
+ config.form.push({ key: 'instructions', type: 'textarea' })
+
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ var rule = { enabled: true };
+ rule.instructions = JSON.parse(form.model.instructions);
+ rule.meta_rule_id = metaRule.id;
+ rule.policy_id = policy.id;
+ rule.rule = [];
+ pushData('subject', form.model, rule.rule);
+ pushData('object', form.model, rule.rule);
+ pushData('action', form.model, rule.rule);
+ policyService.addRuleToPolicy(policy, rule);
+ }
+ }
+
+ self.addRule = function addRule(policy) {
+ var schema = {
+ type: "object",
+ properties: {
+ metaRuleId: { type: "string", title: gettext("Select a Metarule:") }
+ }
+ };
+ var rule = { metaRuleId: null };
+ var titleMap = util.arrayToTitleMap(policy.model.meta_rules);
+ var config = {
+ title: gettext('Add Rule'),
+ schema: schema,
+ form: [{ key: 'metaRuleId', type: 'select', titleMap: titleMap }],
+ model: rule
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ self.addRuleWithMetaRule(policy, modelService.getMetaRule(form.model.metaRuleId));
+ }
+ }
+
+ self.removePolicy = function removePolicy(policy) {
+ if (confirm(gettext('Are you sure to delete this Policy?')))
+ policyService.removePolicy(policy);
+ }
+
+ self.populatePolicy = function populatePolicy(policy) {
+ policyService.populatePolicy(policy);
+ }
+
+ self.removeRuleFromPolicy = function removeRuleFromPolicy(policy, rule) {
+ if (confirm(gettext('Are you sure to delete this Rule?')))
+ policyService.removeRuleFromPolicy(policy, rule);
+ }
+
+ self.showRule = function showRule(rule) {
+ self.selectedRule = rule;
+ }
+
+ self.hideRule = function hideRule() {
+ self.selectedRule = null;
+ self.currentData = null;
+ }
+
+ self.assignData = function assignData(type, policy, data) {
+ self.currentData = {
+ data: data,
+ type: type,
+ loading: true,
+ perimeters: [],
+ assignments: []
+ }
+
+ policyService.loadPerimetersAndAssignments(type, policy).then(function (values) {
+ var category = categoryMap[type];
+ self.currentData.loading = false;
+ self.currentData.perimeters = values.perimeters;
+ for (var index = 0; index < values.assignments.length; index++) {
+ var assignment = values.assignments[index];
+ if (assignment.assignments.indexOf(data.id) >= 0) {
+ var perimeter = values.perimetersMap[assignment[category.perimeterId]];
+ self.currentData.assignments.push(perimeter);
+ self.currentData.perimeters.splice(self.currentData.perimeters.indexOf(perimeter), 1);
+ }
+ }
+ })
+ }
+
+ self.createPerimeter = function createPerimeter(type, policy) {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ description: { type: "string", minLength: 2, title: gettext("Description") },
+ }
+ };
+ if (type == 'subject') {
+ schema.properties.email = { type: "email", "type": "string", "pattern": "^\\S+@\\S+$", title: gettext("Email") }
+ }
+ var perimeter = { name: '', description: '' };
+ var config = {
+ title: gettext('Create Perimeter'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: perimeter
+ };
+ if (type == 'subject') {
+ config.form.push('email');
+ }
+
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createPerimeter(type, policy, form.model).then(function (perimeters) {
+ util.pushAll(self.currentData.perimeters, perimeters);
+ })
+ }
+ }
+
+ self.assign = function assign(type, policy, perimeter, data) {
+ policyService.createAssignment(type, policy, perimeter, data).then(function () {
+ self.currentData.assignments.push(perimeter);
+ self.currentData.perimeters.splice(self.currentData.perimeters.indexOf(perimeter), 1);
+ })
+ }
+
+ self.unassign = function unassign(type, policy, perimeter, data) {
+ policyService.removeAssignment(type, policy, perimeter, data).then(function () {
+ self.currentData.perimeters.push(perimeter);
+ self.currentData.assignments.splice(self.currentData.assignments.indexOf(perimeter), 1);
+ })
+ }
+ }
+})(); \ No newline at end of file
diff --git a/moon_dashboard/moon/static/moon/policy/policy.html b/moon_dashboard/moon/static/moon/policy/policy.html
new file mode 100644
index 00000000..70789fbb
--- /dev/null
+++ b/moon_dashboard/moon/static/moon/policy/policy.html
@@ -0,0 +1,158 @@
+<div ng-controller="moon.policy.controller as ctrl">
+ <div class="clearfix list-group">
+ <div class="pull-right">
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterText">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createPolicy()">
+ <span class="fa fa-plus"></span>
+ <translate>Create Policy</translate>
+ </button>
+ </div>
+ </div>
+
+ <div class="list-group">
+ <div ng-repeat="policy in ctrl.model.policies | orderBy:'name' | filter:filterText" class="list-group-item">
+ <h3 class="list-group-item-heading inline">{$ policy.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash" title="{$ 'Remove Policy' | translate $}" ng-click="ctrl.removePolicy(policy)"></button>
+ <button type="button" class="fa fa-edit" title="{$ 'Edit Policy' | translate $}" ng-click="ctrl.updatePolicy(policy)"></button>
+ </div>
+ <p class="list-group-item-text">{$ policy.description $}</p>
+ <h4 class="list-group-item-text">
+ <translate>Model: {$ policy.model ? policy.model.name : 'none' $}</translate>
+ </h4>
+ <h4 class="list-group-item-text">
+ <translate>Genre:</translate>
+ <translate>{$ policy.genre ? policy.genre : 'none' $}</translate>
+ </h4>
+ <details class="list-group-item-text">
+ <summary ng-click="ctrl.populatePolicy(policy)">
+ <h4 class="inline" translate>Rules</h4>
+ <button type="button" class="fa fa-plus " ng-click="ctrl.addRule(policy)" title="{$ 'Add Rule' | translate $}"></button>
+ </summary>
+ <div class="list-group">
+ <p ng-if="!policy.rules" class="list-group-item-text" translate>Loading rules...</p>
+ <div ng-if="policy.rules" ng-repeat="rule in policy.rules | orderBy:'name'" class="list-group-item">
+ <div class="list-group-item-heading" ng-if="ctrl.selectedRule != rule">
+ <div class="inline-block width-200">
+ <b>
+ <translate>Metarule: </translate>
+ </b> {$ rule.metaRule.name $}
+ </div>
+ <b>
+ <translate>Rule: </translate>
+ </b>
+ <span ng-repeat="data in rule.subjectData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span> |
+ <span ng-repeat="data in rule.actionData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span> |
+ <span ng-repeat="data in rule.objectData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeRuleFromPolicy(policy, rule)" title="{$ 'Remove Rule' | translate $}"></button>
+ <button type="button" class="fa fa-eye pull-right" ng-click="ctrl.showRule(rule)" title="{$ 'Show Rule' | translate $}"></button>
+ </div>
+ </div>
+
+ <div ng-if="ctrl.selectedRule == rule">
+ <h3 class="list-group-item-heading inline">
+ <translate>Metarule: </translate> {$ rule.metaRule.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeRuleFromPolicy(policy, rule)" title="{$ 'Remove Rule' | translate $}"></button>
+ <button type="button" class="fa fa-eye-slash pull-right" ng-click="ctrl.hideRule()" title="{$ 'Hide Rule' | translate $}"></button>
+ </div>
+ <p class="list-group-item-text">
+ <table class="table">
+ <thead>
+ <tr>
+ <th>
+ <span translate>Subjects</span>
+ </th>
+ <th>
+ <span translate>Objects</span>
+ </th>
+ <th>
+ <span translate>Actions</span>
+ </th>
+ <th>
+ <span translate>Instructions</span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p ng-repeat="data in rule.subjectData">
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('subject', policy, data)"
+ title="{$ 'Assign to perimeters' | translate $}"></button>
+ <button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <p ng-repeat="data in rule.objectData">
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('object', policy, data)"
+ title="{$ 'Assign to perimeters' | translate $}"></button>
+ <button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <p ng-repeat="data in rule.actionData">
+ <span ng-class="{'text-primary': ctrl.currentData.data == data}">{$ data.name $}</span>
+ <button ng-if="ctrl.currentData.data != data" type="button" class="fa fa-exchange pull-right" ng-click="ctrl.assignData('action', policy, data)"
+ title="{$ 'Assign to perimeters' | translate $}"></button>
+ <button ng-if="ctrl.currentData.data == data" type="button" class="fa fa-times pull-right" ng-click="ctrl.currentData = null"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <pre ng-bind="rule.instructions | json "></pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div ng-if="ctrl.currentData && ctrl.currentData.loading" class="row padding-10">
+ <h4 translate>Loading...</h4>
+ </div>
+ <div ng-if="ctrl.currentData && !ctrl.currentData.loading" class="row">
+ <div class="padding-10">
+ <h3>
+ <translate>Assign perimeters to</translate> {$ ctrl.currentData.data.name $}</h3>
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterPerimeter">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createPerimeter(ctrl.currentData.type, policy)">
+ <span class="fa fa-plus"></span>
+ <translate>Create Perimeter</translate>
+ </button>
+ </div>
+ <div>
+ <div class="col-lg-4">
+ <h4 translate>Available perimeters</h4>
+ <div class="w-100 height-200 scroll list-group border">
+ <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.perimeters | orderBy:'name' | filter:filterPerimeter" title="{$ perimeter.description $}"
+ ng-click="ctrl.assign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)">{$ perimeter.name $}</button>
+ </div>
+ <p translate class="mt-5">Click to assign</p>
+ </div>
+ <div class="col-lg-4">
+ <h4 translate>Assigned perimeters</h4>
+ <div class="w-100 list-group border height-200 scroll">
+ <button class="list-group-item" ng-repeat="perimeter in ctrl.currentData.assignments | orderBy:'name' | filter:filterPerimeter" title="{$ perimeter.description $}"
+ ng-click="ctrl.unassign(ctrl.currentData.type, policy, perimeter, ctrl.currentData.data)">{$ perimeter.name $}</button>
+ </div>
+ <p translate class="mt-5">Click to unassign</p>
+ </div>
+ </div>
+ </div>
+ </p>
+ </div>
+ </div>
+ </div>
+ </details>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/moon_dashboard/moon/static/moon/policy/policy.service.js b/moon_dashboard/moon/static/moon/policy/policy.service.js
new file mode 100755
index 00000000..87250b2e
--- /dev/null
+++ b/moon_dashboard/moon/static/moon/policy/policy.service.js
@@ -0,0 +1,330 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.policy.service', policyService);
+
+ policyService.$inject = ['moon.util.service', 'moon.model.service', '$resource', 'moon.URI', '$q', 'horizon.framework.widgets.toast.service'];
+
+ function policyService(util, modelService, $resource, URI, $q, toast) {
+ var host = URI.API;
+
+ var policyResource = $resource(host + '/policies/' + ':id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' },
+ update: { method: 'PATCH' }
+ });
+
+ var policyRulesResource = $resource(host + '/policies/' + ':policy_id' + '/rules/' + ':rule_id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ var policySubjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/subject_data/' + ':category_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policyObjectDataResource = $resource(host + '/policies/' + ':policy_id' + '/object_data/' + ':category_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policyActionDataResource = $resource(host + '/policies/' + ':policy_id' + '/action_data/' + ':category_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policySubjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/subjects', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policyObjectPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/objects', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policyActionPerimetersResource = $resource(host + '/policies/' + ':policy_id' + '/actions', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ })
+
+ var policySubjectAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/subject_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ var policyObjectAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/object_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ var policyActionAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/action_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+
+ var categoryMap = {
+ 'subject': {
+ resource: policySubjectDataResource,
+ arrayName: "subjectData",
+ mapName: "subjectDataMap",
+ responseName: "subject_data",
+ perimeterResource: policySubjectPerimetersResource,
+ assignmentResource: policySubjectAssignmentsResource,
+ perimeterResponseName: "subjects",
+ assignmentResponseName: "subject_assignments",
+ },
+ 'object': {
+ resource: policyObjectDataResource,
+ arrayName: "objectData",
+ mapName: "objectDataMap",
+ responseName: "object_data",
+ perimeterResource: policyObjectPerimetersResource,
+ assignmentResource: policyObjectAssignmentsResource,
+ perimeterResponseName: "objects",
+ assignmentResponseName: "object_assignments",
+ },
+ 'action': {
+ resource: policyActionDataResource,
+ arrayName: "actionData",
+ mapName: "actionDataMap",
+ responseName: "action_data",
+ perimeterResource: policyActionPerimetersResource,
+ assignmentResource: policyActionAssignmentsResource,
+ perimeterResponseName: "actions",
+ assignmentResponseName: "action_assignments",
+ }
+ }
+
+ var policiesMap = {};
+ var policies = [];
+
+ function loadPolicies() {
+ var queries = {
+ policies: policyResource.query().$promise,
+ models: modelService.initialize(),
+ }
+
+ $q.all(queries).then(function (result) {
+ createPolicies(result.policies);
+ console.log('moon', 'policies initialized')
+ })
+ }
+
+ function createPolicies(policiesData) {
+ policies.splice(0, policies.length);
+ util.cleanObject(policiesMap);
+ createPolicyInternal(policiesData.policies);
+ }
+
+ function mapPolicy(policy) {
+ if (policy.model_id) {
+ policy.model = modelService.getModel(policy.model_id);
+ }
+ }
+
+ function createPolicyInternal(data) {
+ return util.createInternal(data, policies, policiesMap, mapPolicy);
+ }
+
+ function removePolicyInternal(id) {
+ return util.removeInternal(id, policies, policiesMap);
+ }
+
+ function updatePolicyInternal(data) {
+ return util.updateInternal(data, policiesMap, mapPolicy);
+ }
+
+ function removeRuleInternal(policy, rule) {
+ policy.rules.splice(policy.rules.indexOf(rule), 1);
+ }
+
+ function loadPolicyRule(policy) {
+ if (!policy.rules) {
+ var queries = {
+ rules: policyRulesResource.query({ policy_id: policy.id }).$promise,
+ subjectData: policySubjectDataResource.query({ policy_id: policy.id }).$promise,
+ objectData: policyObjectDataResource.query({ policy_id: policy.id }).$promise,
+ actionData: policyActionDataResource.query({ policy_id: policy.id }).$promise,
+ }
+
+ $q.all(queries).then(function (result) {
+ createRules(policy, result.rules, result.subjectData, result.objectData, result.actionData)
+ }, util.displayErrorFunction('Unable to load rules'))
+ }
+ }
+
+ function createRules(policy, rulesData, subjectsData, objectsData, actionsData) {
+ policy.rules = rulesData ? rulesData.rules.rules : [];
+ policy.subjectDataMap = subjectsData.subject_data.length > 0 ? subjectsData.subject_data[0].data : [];
+ policy.subjectData = util.mapToArray(policy.subjectDataMap);
+ policy.objectDataMap = objectsData.object_data.length > 0 ? objectsData.object_data[0].data : [];
+ policy.objectData = util.mapToArray(policy.objectDataMap);
+ policy.actionDataMap = actionsData.action_data.length > 0 ? actionsData.action_data[0].data : [];
+ policy.actionData = util.mapToArray(policy.actionDataMap);
+ for (var i = 0; i < policy.rules.length; i++) {
+ var rule = policy.rules[i];
+ populateRule(policy, rule);
+ }
+ }
+
+ function populateRule(policy, rule) {
+ if (rule.meta_rule_id) {
+ rule.metaRule = modelService.getMetaRule(rule.meta_rule_id);
+ }
+ if (rule.metaRule) {
+ var j = 0;
+ var k, id;
+ rule.subjectData = [];
+ rule.objectData = [];
+ rule.actionData = [];
+ for (k = 0; k < rule.metaRule.subject_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.subjectData.push(policy.subjectDataMap[id]);
+ }
+ j += k;
+ for (k = 0; k < rule.metaRule.object_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.objectData.push(policy.objectDataMap[id]);
+ }
+ j += k;
+ for (k = 0; k < rule.metaRule.action_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.actionData.push(policy.actionDataMap[id]);
+ }
+ }
+ return rule;
+ }
+
+ return {
+ initialize: loadPolicies,
+ createPolicies: createPolicies,
+ policies: policies,
+ getPolicy: function getPolicy(id) {
+ return policiesMap[id];
+ },
+ createPolicy: function createPolicy(policy) {
+ policyResource.create(null, policy, success, util.displayErrorFunction('Unable to create Policy'));
+
+ function success(data) {
+ createPolicyInternal(data.policies);
+ util.displaySuccess('Policy created');
+ }
+ },
+ removePolicy: function removePolicy(policy) {
+ policyResource.remove({ id: policy.id }, null, success, util.displayErrorFunction('Unable to remove Policy'));
+
+ function success(data) {
+ removePolicyInternal(policy.id);
+ util.displaySuccess('Policy removed');
+ }
+ },
+ updatePolicy: function updatePolicy(policy) {
+ policyResource.update({ id: policy.id }, policy, success, util.displayErrorFunction('Unable to update Policy'));
+
+ function success(data) {
+ updatePolicyInternal(data.policies)
+ util.displaySuccess('Policy updated');
+ }
+ },
+ populatePolicy: loadPolicyRule,
+ createRules: createRules,
+ addRuleToPolicy: function addRuleToPolicy(policy, rule) {
+ policyRulesResource.create({ policy_id: policy.id }, rule, success, util.displayErrorFunction('Unable to create Rule'));
+
+ function success(data) {
+ var rules = util.mapToArray(data.rules);
+ for (var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ policy.rules.push(populateRule(policy, rule))
+ }
+ util.displaySuccess('Rule created');
+ }
+ },
+ removeRuleFromPolicy: function removeRuleFromPolicy(policy, rule) {
+ policyRulesResource.remove({ policy_id: policy.id, rule_id: rule.id }, null, success, util.displayErrorFunction('Unable to remove Rule'));
+
+ function success(data) {
+ removeRuleInternal(policy, rule);
+ util.displaySuccess('Rule removed');
+ }
+ },
+ createData: function createData(type, policy, category, dataCategory) {
+ var categoryValue = categoryMap[type];
+ return categoryValue.resource.create({ policy_id: policy.id, category_id: category.id }, dataCategory).$promise.then(
+ function (data) {
+ var result = util.createInternal(data[categoryValue.responseName].data, policy[categoryValue.arrayName], policy[categoryValue.mapName]);
+ util.displaySuccess('Data created');
+ return result;
+ },
+ util.displayErrorFunction('Unable to create Data')
+ );
+ },
+ createPerimeter: function createPerimeter(type, policy, perimeter) {
+ var categoryValue = categoryMap[type];
+ return categoryValue.perimeterResource.create({ policy_id: policy.id }, perimeter).$promise.then(
+ function (data) {
+ util.displaySuccess('Perimeter created');
+ return util.mapToArray(data[categoryValue.perimeterResponseName]);
+ },
+ util.displayErrorFunction('Unable to create Perimeter')
+ );
+ },
+ loadPerimetersAndAssignments: function loadPerimetersAndAssignments(type, policy) {
+ var categoryValue = categoryMap[type];
+ var queries = {
+ perimeters: categoryValue.perimeterResource.query({ policy_id: policy.id }).$promise,
+ assignments: categoryValue.assignmentResource.query({ policy_id: policy.id }).$promise,
+ }
+
+ return $q.all(queries).then(function (data) {
+ var result = {};
+ result.assignments = util.mapToArray(data.assignments[categoryValue.assignmentResponseName]);
+ result.perimetersMap = data.perimeters[categoryValue.perimeterResponseName];
+ result.perimeters = util.mapToArray(result.perimetersMap);
+ return result;
+ }, util.displayErrorFunction('Unable to load Perimeters'))
+
+ },
+ createAssignment: function createAssignment(type, policy, perimeter, data) {
+ var categoryValue = categoryMap[type];
+ var assignment = {
+ "id": perimeter.id,
+ "category_id": data.category_id,
+ "data_id": data.id,
+ "policy_id": policy.id
+ }
+ return categoryValue.assignmentResource.create({ policy_id: policy.id }, assignment).$promise.then(
+ function (data) {
+ util.displaySuccess('Assignment created');
+ return util.mapToArray(data[categoryValue.assignmentResponseName]);
+ },
+ util.displayErrorFunction('Unable to create Assignment')
+ )
+ },
+ removeAssignment: function removeAssignment(type, policy, perimeter, data) {
+ var categoryValue = categoryMap[type];
+
+ return categoryValue.assignmentResource.remove({ policy_id: policy.id, perimeter_id: perimeter.id, category_id: data.category_id, data_id: data.id }, null).$promise.then(
+ function (data) {
+ util.displaySuccess('Assignment removed');
+ },
+ util.displayErrorFunction('Unable to remove Assignment')
+ )
+ },
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/moon_dashboard/moon/static/moon/policy/policy.service.spec.js b/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
new file mode 100755
index 00000000..045bf9b3
--- /dev/null
+++ b/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
@@ -0,0 +1,336 @@
+(function () {
+ 'use strict';
+
+ describe('moon.policy.service', function () {
+ var service, modelService, $httpBackend, URI;
+ var policiesData;
+ var modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData;
+ var rulesData, subjectsData, objectsData, actionsData;
+
+
+ function initData() {
+ policiesData = {
+ policies:
+ {
+ 'policyId1': { name: 'policy1', description: 'pDescription1', genre: 'genre1', model_id: 'modelId1' },
+ }
+ };
+
+ modelsData = {
+ models:
+ { 'modelId1': { name: 'model1', description: 'mDescription1', meta_rules: ['metaRuleId1'] } }
+ };
+
+ subjectCategoriesData = {
+ subject_categories:
+ {
+ 'subjectCategoryId1': { name: 'subjectCategory1', description: 'scDescription1' },
+ 'subjectCategoryId2': { name: 'subjectCategory2', description: 'scDescription2' }
+ },
+ };
+ objectCategoriesData = {
+ object_categories:
+ {
+ 'objectCategoryId1': { name: 'objectCategory1', description: 'ocDescription1' },
+ 'objectCategoryId2': { name: 'objectCategory2', description: 'ocDescription2' }
+ }
+ };
+ actionCategoriesData = {
+ action_categories:
+ {
+ 'actionCategoryId1': { name: 'actionCategory1', description: 'acDescription1' },
+ 'actionCategoryId2': { name: 'actionCategory2', description: 'acDescription2' }
+ }
+ };
+ metaRulesData = {
+ meta_rules:
+ {
+ 'metaRuleId1': { name: 'metaRule1', description: 'mrDescription1', subject_categories: ['subjectCategoryId1'], object_categories: ['objectCategoryId1'], action_categories: ['actionCategoryId1'] },
+ 'metaRuleId2': { name: 'metaRule2', description: 'mrDescription2', subject_categories: [], object_categories: [], action_categories: [] }
+ }
+ };
+ }
+
+ function initRuleData() {
+ rulesData = {
+ rules: {
+ rules: [
+ { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], id: 'ruleId1', instructions: { test: 'test' } }
+ ]
+ }
+ };
+
+ subjectsData = {
+ subject_data:
+ [
+ {
+ data: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ }
+ ]
+ };
+ objectsData = {
+ object_data:
+ [
+ {
+ data: {
+ 'objectId1': { name: 'object1', description: 'oDescription1' },
+ }
+ }
+ ]
+ };
+ actionsData = {
+ action_data:
+ [
+ {
+ data: {
+ 'actionId1': { name: 'action1', description: 'aDescription1' },
+ }
+ }
+ ]
+ };
+ }
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.framework'));
+ beforeEach(module('moon'));
+
+ beforeEach(inject(function ($injector) {
+ service = $injector.get('moon.policy.service');
+ modelService = $injector.get('moon.model.service');
+ $httpBackend = $injector.get('$httpBackend');
+ URI = $injector.get('moon.URI');
+ }));
+
+ afterEach(function () {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ it('should initialize', function () {
+ initData();
+ $httpBackend.expectGET(URI.API + '/policies').respond(200, policiesData);
+ $httpBackend.expectGET(URI.API + '/subject_categories').respond(200, subjectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/object_categories').respond(200, objectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/action_categories').respond(200, actionCategoriesData);
+ $httpBackend.expectGET(URI.API + '/meta_rules').respond(200, metaRulesData);
+ $httpBackend.expectGET(URI.API + '/models').respond(200, modelsData);
+
+
+ service.initialize();
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy1');
+ expect(policy.description).toBe('pDescription1');
+ expect(policy.genre).toBe('genre1');
+ expect(policy.model.id).toBe('modelId1');
+
+ });
+
+
+
+ it('should create policy', function () {
+ initData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ var policyCreatedData = {
+ policies:
+ { 'policyId1': { name: 'policy1', description: 'pDescription1', genre: 'genre1', model_id: 'modelId1' } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/policies').respond(200, policyCreatedData);
+
+ service.createPolicy({ name: 'policy1', description: 'pDescription1', genre: 'genre1', model: modelService.getModel('modelId1') });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy1');
+ expect(policy.description).toBe('pDescription1');
+ expect(policy.genre).toBe('genre1');
+ expect(policy.model.id).toBe('modelId1');
+ });
+
+ it('should remove policy', function () {
+ initData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1').respond(200);
+
+ service.removePolicy({ id: 'policyId1' });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(0);
+ });
+
+ it('should update policy', function () {
+ initData();
+ var policyUpdatedData = {
+ policies:
+ { 'policyId1': { name: 'policy2', description: 'pDescription2', genre: 'genre2', model_id: 'modelId1' } }
+ };
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ $httpBackend.expectPATCH(URI.API + '/policies/policyId1').respond(200, policyUpdatedData);
+
+ service.updatePolicy({ id: 'policyId1', name: 'policy2', description: 'pDescription2', genre: 'genre2', model: modelService.getModel('modelId1') });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy2');
+ expect(policy.description).toBe('pDescription2');
+ expect(policy.genre).toBe('genre2');
+ expect(policy.model.id).toBe('modelId1');
+
+ });
+
+
+ it('should populate policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ var policy = service.getPolicy('policyId1')
+
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/rules').respond(200, rulesData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/subject_data').respond(200, subjectsData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/object_data').respond(200, objectsData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/action_data').respond(200, actionsData);
+
+ service.populatePolicy(policy);
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(1);
+ var rule = policy.rules[0];
+ expect(rule.id).toBe('ruleId1');
+ expect(rule.metaRule.id).toBe('metaRuleId1');
+ expect(rule.instructions.test).toBe('test');
+ expect(rule.subjectData.length).toBe(1);
+ expect(rule.subjectData[0].id).toBe('subjectId1');
+ expect(rule.objectData.length).toBe(1);
+ expect(rule.objectData[0].id).toBe('objectId1');
+ expect(rule.actionData.length).toBe(1);
+ expect(rule.actionData[0].id).toBe('actionId1');
+
+ expect(policy.subjectData.length).toBe(1);
+ var subjectData = policy.subjectData[0];
+ expect(subjectData.id).toBe('subjectId1');
+ expect(subjectData.name).toBe('subject1');
+ expect(subjectData.description).toBe('sDescription1');
+
+ expect(policy.objectData.length).toBe(1);
+ var objectData = policy.objectData[0];
+ expect(objectData.id).toBe('objectId1');
+ expect(objectData.name).toBe('object1');
+ expect(objectData.description).toBe('oDescription1');
+
+ expect(policy.actionData.length).toBe(1);
+ var actionData = policy.actionData[0];
+ expect(actionData.id).toBe('actionId1');
+ expect(actionData.name).toBe('action1');
+ expect(actionData.description).toBe('aDescription1');
+
+ });
+
+
+ it('should add rule to policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+
+ var ruleCreatedData = {
+ rules: {
+ 'ruleId1': { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], instructions: { test: 'test' } }
+ }
+ };
+
+ var policy = service.getPolicy('policyId1');
+
+ service.createRules(policy, null, subjectsData, objectsData, actionsData);
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/rules').respond(200, ruleCreatedData);
+
+ service.addRuleToPolicy(policy, { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], instructions: { test: 'test' } });
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(1);
+ var rule = policy.rules[0];
+ expect(rule.id).toBe('ruleId1');
+ expect(rule.metaRule.id).toBe('metaRuleId1');
+ expect(rule.subjectData.length).toBe(1);
+ expect(rule.subjectData[0].id).toBe('subjectId1');
+ expect(rule.objectData.length).toBe(1);
+ expect(rule.objectData[0].id).toBe('objectId1');
+ expect(rule.actionData.length).toBe(1);
+ expect(rule.actionData[0].id).toBe('actionId1');
+
+ });
+
+ it('should remove rule from policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ var policy = service.getPolicy('policyId1');
+
+ service.createRules(policy, rulesData, subjectsData, objectsData, actionsData);
+
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1/rules/ruleId1').respond(200);
+
+ service.removeRuleFromPolicy(policy, { id: 'ruleId1' });
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(0);
+ });
+
+
+ it('should create data', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+
+ var dataCreatedData = {
+ subject_data: {
+ data: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ }
+ };
+
+ var policy = service.getPolicy('policyId1');
+ policy.subjectData = [];
+ policy.subjectDataMap = {};
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/subject_data/subjectCategoryId1').respond(200, dataCreatedData);
+
+ service.createData('subject', policy, modelService.getCategory('subject', 'subjectCategoryId1'), { name: 'subject1', description: 'sDescription1' });
+ $httpBackend.flush();
+
+ expect(policy.subjectData.length).toBe(1);
+ var subjectData = policy.subjectData[0];
+ expect(subjectData.id).toBe('subjectId1');
+ expect(subjectData.name).toBe('subject1');
+ expect(subjectData.description).toBe('sDescription1');
+
+ });
+
+
+ });
+
+
+})(); \ No newline at end of file