Commit 5eee1f9c authored by Jochen Kressin's avatar Jochen Kressin
Browse files

added sanity check based on new mtinfo endpoint

parent 7e651af1
#!/bin/bash
PLUGIN_NAME=searchguard-kibana
PLUGIN_VERSION=5.2.2-beta2
PLUGIN_VERSION=5.3.0-beta3
echo "Building $PLUGIN_NAME-$PLUGIN_VERSION.zip"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR/..
......
......@@ -79,6 +79,9 @@ export default function (kibana) {
injectDefaultVars(server, options) {
options.multitenancy_enabled = server.config().get('searchguard.multitenancy.enabled');
options.basicauth_enabled = server.config().get('searchguard.basicauth.enabled');
options.kibana_index = server.config().get('kibana.index');
options.kibana_server_user = server.config().get('elasticsearch.username');
return options;
}
......
......@@ -66,6 +66,23 @@ export default class SearchGuardBackend {
}
}
async multitenancyinfo(authHeader) {
try {
const response = await this._client.searchguard.multitenancyinfo({
headers: {
authorization: authHeader
}
});
return response
} catch(error) {
if (error.status == 401) {
throw new AuthenticationError();
} else {
throw error;
}
}
}
async getAuthHeaders(user) {
const credentials = user.proxyCredentials;
const authHeader = new Buffer(`${credentials.username}:${credentials.password}`).toString('base64');
......
......@@ -29,5 +29,11 @@ export default function (Client, config, components) {
fmt: '_searchguard/authinfo'
}
});
Client.prototype.searchguard.prototype.multitenancyinfo = ca({
url: {
fmt: '_searchguard/kibanainfo'
}
});
};
......@@ -27,7 +27,7 @@ module.exports = function (pluginRoot, server, kbnServer, APP_ROOT, API_ROOT) {
server.route({
method: 'POST',
path: `${API_ROOT}/v1/tenant`,
path: `${API_ROOT}/v1/multitenancy/tenant`,
handler: (request, reply) => {
var username = request.payload.username;
var selectedTenant = request.payload.tenant;
......@@ -38,9 +38,21 @@ module.exports = function (pluginRoot, server, kbnServer, APP_ROOT, API_ROOT) {
server.route({
method: 'GET',
path: `${API_ROOT}/v1/tenant`,
path: `${API_ROOT}/v1/multitenancy/tenant`,
handler: (request, reply) => {
return reply(request.state.searchguard_tenant);
}
});
server.route({
method: 'GET',
path: `${API_ROOT}/v1/multitenancy/info`,
handler: (request, reply) => {
let mtinfo = server.plugins.searchguard.getSearchGuardBackend().multitenancyinfo(request.headers.authorization);
return reply(mtinfo);
}
});
}; //end module
{
"name": "searchguard",
"version": "5.2.2",
"version": "5.3.0",
"description": "Search Guard features for kibana",
"main": "index.js",
"homepage": "https://floragunn.com",
......
......@@ -12,70 +12,70 @@
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="page-header">
<h2 class="text-center">Available tenants</h2>
<h4 class="text-center" ng-bind="ctrl.tenantLabel"></h4>
<p class="error-message" ng-if="ctrl.errorMessage" ng-bind="ctrl.errorMessage"></p>
<h5 class="error-message" ng-if="ctrl.errorMessage" ng-bind="ctrl.errorMessage"></h5>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<table class="kuiTable">
<table class="table">
<thead>
<tr>
<th class="kuiTableHeaderCell">Name</th>
<th class="kuiTableHeaderCell">Permissions</th>
<th class="kuiTableHeaderCell actions">Action</th>
</tr>
<tr>
<th class="kuiTableHeaderCell">Name</th>
<th class="kuiTableHeaderCell">Permissions</th>
<th class="kuiTableHeaderCell kuiTableHeaderCell--alignRight">Action</th>
</tr>
</thead>
<tbody>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ''}" ng-show="ctrl.globalEnabled">
<td class="kuiTableRowCell">
{{ctrl.GLOBAL_USER_LABEL}}
</td>
<td class="kuiTableRowCell">
<div>read/write</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == ''"
ng-show="ctrl.currentTenant != ctrl.GLOBAL_USER_VALUE"
ng-click="ctrl.selectTenant(ctrl.GLOBAL_USER_LABEL, ctrl.GLOBAL_USER_VALUE)">Select
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE}" ng-show="ctrl.privateEnabled">
<td class="kuiTableRowCell">
{{ctrl.PRIVATE_USER_LABEL}}
</td>
<td class="kuiTableRowCell">
<div>read/write</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE"
ng-click="ctrl.selectTenant(ctrl.PRIVATE_USER_LABEL, ctrl.PRIVATE_USER_VALUE)">Select
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ''}" ng-show="ctrl.globalEnabled">
<td class="kuiTableRowCell">
{{ctrl.GLOBAL_USER_LABEL}}
</td>
<td class="kuiTableRowCell">
<div ng-if="ctrl.GLOBAL_USER_WRITEABLE">read/write</div>
<div ng-if="!ctrl.GLOBAL_USER_WRITEABLE">read only</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == ''"
ng-show="ctrl.currentTenant != ctrl.GLOBAL_USER_VALUE"
ng-click="ctrl.selectTenant(ctrl.GLOBAL_USER_LABEL, ctrl.GLOBAL_USER_VALUE)">Select
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE}" ng-show="ctrl.privateEnabled">
<td class="kuiTableRowCell">
{{ctrl.PRIVATE_USER_LABEL}}
</td>
<td class="kuiTableRowCell">
<div>read/write</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE"
ng-click="ctrl.selectTenant(ctrl.PRIVATE_USER_LABEL, ctrl.PRIVATE_USER_VALUE)">Select
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-repeat="tenantkey in ctrl.tenantkeys" ng-class="{'selected': tenantkey == ctrl.currentTenant}">
<td class="kuiTableRowCell">
{{tenantkey}}
</td>
<td class="kuiTableRowCell">
<div ng-if="ctrl.tenants[tenantkey]">read/write</div>
<div ng-if="!ctrl.tenants[tenantkey]">read only</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(tenantkey, tenantkey)">Select
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-repeat="tenantkey in ctrl.tenantkeys" ng-class="{'selected': tenantkey == ctrl.currentTenant}">
<td class="kuiTableRowCell">
{{tenantkey}}
</td>
<td class="kuiTableRowCell">
<div ng-if="ctrl.tenants[tenantkey]">read/write</div>
<div ng-if="!ctrl.tenants[tenantkey]">read only</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(tenantkey, tenantkey)">Select
</button>
</td>
</tr>
</tbody>
</table>
</div>
......
......@@ -40,15 +40,49 @@ uiModules
var API_ROOT = `${APP_ROOT}/api/v1`;
let notify = new Notifier({});
const kibana_server_user = chrome.getInjected("kibana_server_user");
const kibana_index = chrome.getInjected("kibana_index");
this.privateEnabled = chrome.getInjected("multitenancy.tenants.enable_private");
this.globalEnabled = chrome.getInjected("multitenancy.tenants.enable_global");
this.GLOBAL_USER_LABEL = "Global";
this.GLOBAL_USER_VALUE = null;
this.GLOBAL_USER_WRITEABLE = true;
this.PRIVATE_USER_LABEL = "Private";
this.PRIVATE_USER_VALUE = "__user__";
this.currentTenant = null;
$http.get(`${API_ROOT}/multitenancy/info`)
.then(
(response) => {
// sanity checks, check that configuration is correct on
// both ES and KI side
var mtinfo = response.data;
this.GLOBAL_USER_WRITEABLE = !mtinfo.kibana_index_readonly;
if(!mtinfo.kibana_mt_enabled) {
this.errorMessage = "It seems that the Multitenancy module is not installed on your Elasticsearch cluster. Multitenancy will not work, please check your installation.";
return;
}
if(mtinfo.kibana_server_user != kibana_server_user) {
this.errorMessage = "Mismatch between the configured Kibana server usernames on Elasticsearch and Kibana, multitenancy will not work! " +
"Configured username on Kibana: '"+kibana_server_user+"', configured username on Elasticsearch: '"+mtinfo.kibana_server_user+"'";
return;
}
if(mtinfo.kibana_index != kibana_index) {
this.errorMessage = "Mismatch between the configured Kibana index names on Elasticsearch and Kibana, multitenancy will not work! " +
"Configured index name on Kibana: '"+kibana_index+"', configured index name on Elasticsearch: '"+mtinfo.kibana_index+"'";
return;
}
},
(error) => notify.error(error)
);
$http.get(`${API_ROOT}/auth/authinfo`)
.then(
(response) => {
......@@ -72,11 +106,11 @@ uiModules
this.tenants = allTenants;
this.tenantkeys = tenantkeys;
$http.get(`${API_ROOT}/tenant`)
$http.get(`${API_ROOT}/multitenancy/tenant`)
.then(
(response) => {
this.currentTenant = response.data;
this.tenantLabel = "Selected tenant: " + resolveTenantName(this.currentTenant, this.username);
this.tenantLabel = "Active tenant: " + resolveTenantName(this.currentTenant, this.username);
},
(error) => notify.error(error)
);
......@@ -86,10 +120,10 @@ uiModules
this.selectTenant = function (tenantLabel, tenant) {
$http.post(`${API_ROOT}/tenant`, {tenant: tenant, username: this.username})
$http.post(`${API_ROOT}/multitenancy/tenant`, {tenant: tenant, username: this.username})
.then(
(response) => {
this.tenantLabel = "Selected tenant: " + resolveTenantName(response.data, this.username);
this.tenantLabel = "Active tenant: " + resolveTenantName(response.data, this.username);
this.currentTenant = response.data;
// clear lastUrls from nav links to avoid not found errors
chrome.getNavLinkById("kibana:visualize").lastSubUrl = chrome.getNavLinkById("kibana:visualize").url;
......@@ -97,7 +131,7 @@ uiModules
chrome.getNavLinkById("kibana:discover").lastSubUrl = chrome.getNavLinkById("kibana:discover").url;
chrome.getNavLinkById("timelion").lastSubUrl = chrome.getNavLinkById("timelion").url;
sessionStorage.clear();
notify.info("Tenant changed");
// notify.info("Tenant changed");
},
(error) => notify.error(error)
);
......
......@@ -9,6 +9,16 @@
background-color: #eee;
}
.kuiTableRowCell {
padding: 7px 8px 8px;
}
.error-message {
font-weight: bold;
color: red;
text-align: center;
}
.btn-default {
background-color: #73b626;
border-bottom-color: #73b626;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment