RBAC React Component, displays/hides components based on role
Signed-off-by: Laurence Maultsby <laurence.maultsby@riftio.com>
diff --git a/skyquake/framework/core/modules/api/projectManagementAPI.js b/skyquake/framework/core/modules/api/projectManagementAPI.js
index 3238aec..07e873d 100644
--- a/skyquake/framework/core/modules/api/projectManagementAPI.js
+++ b/skyquake/framework/core/modules/api/projectManagementAPI.js
@@ -178,14 +178,18 @@
}
-ProjectManagement.getPlatform = function(req) {
+ProjectManagement.getPlatform = function(req, userId) {
var self = this;
var api_server = req.query['api_server'];
-
+ var user = req.params['userId'] || userId;
return new Promise(function(resolve, reject) {
+ var url = utils.confdPort(api_server) + '/api/operational/rbac-platform-config';
+ if(user) {
+ url = url + '/user/' + user;
+ }
Promise.all([
rp({
- uri: utils.confdPort(api_server) + '/api/operational/rbac-platform-config',
+ uri: url,
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
'Authorization': req.session && req.session.authorization
@@ -198,7 +202,11 @@
var response = {};
response['data'] = {};
if (result[0].body) {
- response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:rbac-platform-config'];
+ if(user) {
+ response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:user'];
+ } else {
+ response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:rbac-platform-config'];
+ }
}
response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
diff --git a/skyquake/framework/core/modules/api/userManagementAPI.js b/skyquake/framework/core/modules/api/userManagementAPI.js
index 0608c5d..873ab19 100644
--- a/skyquake/framework/core/modules/api/userManagementAPI.js
+++ b/skyquake/framework/core/modules/api/userManagementAPI.js
@@ -25,6 +25,7 @@
var constants = require('../../api_utils/constants');
var utils = require('../../api_utils/utils');
var _ = require('lodash');
+var ProjectManagementAPI = require('./projectManagementAPI.js');
UserManagement.get = function(req) {
var self = this;
@@ -63,20 +64,96 @@
});
};
+
UserManagement.getProfile = function(req) {
var self = this;
var api_server = req.query['api_server'];
return new Promise(function(resolve, reject) {
var response = {};
- response['data'] = {
- userId: req.session.userdata.username,
+ var userId = req.session.userdata.username
+ response['data'] = {
+ userId: userId,
projectId: req.session.projectId
};
- response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+ UserManagement.getUserInfo(req, userId).then(function(result) {
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+ response.data.data =result.data
+ resolve(response);
+ }, function(error) {
+ console.log('Error retrieving getUserInfo');
+ response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.INTERNAL_SERVER_ERROR;
+ reject(response);
+ })
- resolve(response);
});
};
+UserManagement.getUserInfo = function(req, userId, domain) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var id = req.params['userId'] || userId;
+ var domain = req.params['domainId'] || domain;
+ var response = {};
+ return new Promise(function(resolve, reject) {
+ if (id) {
+ var getProjects = ProjectManagementAPI.get(req)
+ var getPlatformUser = ProjectManagementAPI.getPlatform(req, id)
+ Promise.all([
+ getProjects,
+ getPlatformUser
+ ]).then(function(result) {
+ var userData = {
+ platform: {
+ role: {
+
+ }
+ },
+ project: {
+ /**
+ * [projectId] : {
+ * data: [project object],
+ * role: {
+ * [roleId]: true
+ * }
+ * }
+ */
+ }
+ }
+ //Build project roles
+ var projects = result[0].data.project;
+ var userProjects = [];
+ projects && projects.map(function(p, i) {
+ var users = p['project-config'] && p['project-config'].user;
+ users && users.map(function(u) {
+ if(u['user-name'] == id) {
+ userData.project[p.name] = {
+ data: p,
+ role: {}
+ }
+ u.role.map(function(r) {
+ userData.project[p.name].role[r.role] = true
+ });
+ }
+ })
+ });
+ //Build platform roles
+ var platformRoles = result[1].data.platform && result[1].data.platform.role;
+ platformRoles && platformRoles.map(function(r) {
+ userData.platform.role[r.role] = true
+ });
+ response.data = userData;
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+ resolve(response);
+ })
+ } else {
+ var errorMsg = 'userId not specified in UserManagement.getUserInfo';
+ console.error(errorMsg);
+ response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST;
+ response.error = errorMsg;
+ reject(response)
+ }
+
+ })
+}
UserManagement.create = function(req) {
var self = this;
var api_server = req.query['api_server'];
diff --git a/skyquake/framework/core/modules/navigation_manager.js b/skyquake/framework/core/modules/navigation_manager.js
index 6ed1e49..f690359 100644
--- a/skyquake/framework/core/modules/navigation_manager.js
+++ b/skyquake/framework/core/modules/navigation_manager.js
@@ -68,6 +68,13 @@
NAVIGATION[plugin_name].label = label || 'RW.UI Plugin';
}
+function addAllow(plugin_name, allow) {
+ if (!NAVIGATION[plugin_name]) {
+ NAVIGATION[plugin_name] = {};
+ }
+ NAVIGATION[plugin_name].allow = allow || '*';
+}
+
function getNavigation() {
return NAVIGATION;
}
@@ -81,6 +88,7 @@
addOrder(plugin_name, plugin.order);
addPriority(plugin_name, plugin.priority);
addLabel(plugin_name, plugin.name);
+ addAllow(plugin_name, plugin.allow);
}
function init() {
diff --git a/skyquake/framework/core/modules/routes/projectManagement.js b/skyquake/framework/core/modules/routes/projectManagement.js
index ef52ba3..c106f30 100644
--- a/skyquake/framework/core/modules/routes/projectManagement.js
+++ b/skyquake/framework/core/modules/routes/projectManagement.js
@@ -1,4 +1,3 @@
-
/*
*
* Copyright 2016 RIFT.IO Inc
diff --git a/skyquake/framework/core/modules/routes/userManagement.js b/skyquake/framework/core/modules/routes/userManagement.js
index 4e272d0..22a2d74 100644
--- a/skyquake/framework/core/modules/routes/userManagement.js
+++ b/skyquake/framework/core/modules/routes/userManagement.js
@@ -50,6 +50,13 @@
utils.sendErrorResponse(error, res);
});
});
+Router.get('/user-data/:userId/:domain?', cors(), function(req, res) {
+ UserManagementAPI.getUserInfo(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
Router.post('/user', cors(), function(req, res) {
UserManagementAPI.create(req).then(function(response) {
utils.sendSuccessResponse(response, res);
diff --git a/skyquake/framework/utils/roleConstants.js b/skyquake/framework/utils/roleConstants.js
new file mode 100644
index 0000000..95e36fc
--- /dev/null
+++ b/skyquake/framework/utils/roleConstants.js
@@ -0,0 +1,16 @@
+var c = {};
+
+c.PLATFORM = {
+ OPER: "rw-rbac-platform:platform-oper",
+ ADMIN: "rw-rbac-platform:platform-admin",
+ SUPER: "rw-rbac-platform:super-admin"
+}
+
+c.PROJECT = {
+ MANO_OPER: "rw-project-mano:mano-oper",
+ MANO_ADMIN: "rw-project-mano:mano-admin",
+ PROJECT_ADMIN: "rw-project:project-admin",
+ PROJECT_OPER: "rw-project:project-oper",
+}
+
+module.exports = c;
diff --git a/skyquake/framework/widgets/skyquake_nav/skyquakeNav.jsx b/skyquake/framework/widgets/skyquake_nav/skyquakeNav.jsx
index 51a21a0..a752bf6 100644
--- a/skyquake/framework/widgets/skyquake_nav/skyquakeNav.jsx
+++ b/skyquake/framework/widgets/skyquake_nav/skyquakeNav.jsx
@@ -25,6 +25,7 @@
import './skyquakeNav.scss';
import SelectOption from '../form_controls/selectOption.jsx';
import {FormSection} from '../form_controls/formControls.jsx';
+import SkyquakeRBAC from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
//Temporary, until api server is on same port as webserver
var rw = require('utils/rw.js');
@@ -298,14 +299,14 @@
navItem.priority = nav[k].priority;
navItem.order = nav[k].order;
navItem.html = (
- <div key={k} className={navClass}>
+ <SkyquakeRBAC allow={nav[k].allow || ['*']} key={k} className={navClass}>
<h2>{dashboardLink} {self.hasSubNav[k] ? <span className="oi" data-glyph="caret-bottom"></span> : ''}</h2>
<ul className="menu">
{
NavList
}
</ul>
- </div>
+ </SkyquakeRBAC>
);
navList.push(navItem)
}
diff --git a/skyquake/framework/widgets/skyquake_rbac/skyquakeRBAC.jsx b/skyquake/framework/widgets/skyquake_rbac/skyquakeRBAC.jsx
new file mode 100644
index 0000000..e00e672
--- /dev/null
+++ b/skyquake/framework/widgets/skyquake_rbac/skyquakeRBAC.jsx
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+import React from 'react';
+import ROLES from 'utils/roleConstants.js';
+const PLATFORM = ROLES.PLATFORM;
+
+export default class SkyquakeRBAC extends React.Component {
+ constructor(props, context) {
+ super(props);
+ }
+ render() {
+ const User = this.context.userProfile.data;
+ let HTML = null;
+ // If user object has platform property then it has been populated by the back end.
+ if(User) {
+ const PlatformRole = User.platform.role;
+ const isPlatformSuper = PlatformRole[PLATFORM.SUPER];
+ const isPlatformAdmin = PlatformRole[PLATFORM.ADMIN];
+ const isPlatformOper = PlatformRole[PLATFORM.OPER];
+ const hasRoleAccess = checkForRoleAccess(User.project[this.props.project], PlatformRole, this.props.allow)//false//(this.props.roles.indexOf(userProfile.projectRole) > -1)
+ if (isPlatformSuper) {
+ HTML = this.props.children;
+ } else {
+ if (hasRoleAccess) {
+ HTML = this.props.children;
+ }
+ }
+ }
+ return (<div className={this.props.className} style={this.props.style}>{HTML}</div>)
+ }
+}
+SkyquakeRBAC.defaultProps = {
+ allow: []
+}
+SkyquakeRBAC.contextTypes = {
+ userProfile: React.PropTypes.object
+}
+
+function checkForRoleAccess(project, PlatformRole, allow) {
+ if (allow.indexOf('*') > -1) return true;
+ for (let i = 0; i<allow.length; i++) {
+ if((project && project.role[allow[i]] )|| PlatformRole[allow[i]]) {
+ return true
+ }
+ }
+ return false;
+ }
+
+
+
+// export default function(Component) {
+// class SkyquakeRBAC extends React.Component {
+// constructor(props, context) {
+// super(props);
+// }
+// render(props) {
+// console.log(this.context.userProfile)
+// const User = this.context.userProfile.data;
+// // If user object has platform property then it has been populated by the back end.
+// if(User) {
+// const PlatformRole = User.platform.role;
+// const HTML = <Component {...this.props} router={this.router} actions={this.actions} flux={this.context.flux}/>;
+// const isPlatformSuper = PlatformRole[PLATFORM.SUPER];
+// const isPlatformAdmin = PlatformRole[PLATFORM.ADMIN];
+// const isPlatformOper = PlatformRole[PLATFORM.OPER];
+// const hasRoleAccess = false//(this.props.roles.indexOf(userProfile.projectRole) > -1)
+// if (isPlatformSuper || isPlatformOper || isPlatformAdmin) {
+// return HTML
+// } else {
+// if (hasRoleAccess) {
+// return HTML
+// } else {
+// return null;
+// }
+// }
+// }
+// else {
+// return null;
+
+// }
+// }
+// }
+// SkyquakeRBAC.defaultProps = {
+
+// }
+// SkyquakeRBAC.contextTypes = {
+// userProfile: React.PropTypes.object,
+// allowedRoles: []
+// };
+// return SkyquakeRBAC;
+// }