Commit 3fbe83fe authored by Jochen Kressin's avatar Jochen Kressin
Browse files

display username and roles, added direct links to dashboards and...

display username and roles, added direct links to dashboards and visualizations, added filter for tenants
parent 47f143c3
#!/bin/bash
PLUGIN_NAME=searchguard-kibana
PLUGIN_VERSION=5.3.0-beta3.1
KIBANA_VERSION=5.3.0
PLUGIN_VERSION=5.2.2-GA
KIBANA_VERSION=5.2.2
echo "Building $PLUGIN_NAME-$PLUGIN_VERSION.zip"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR/..
......
......@@ -38,6 +38,8 @@ export default function (kibana) {
}).default(),
multitenancy: Joi.object().keys({
enabled: Joi.boolean().default(false),
show_roles: Joi.boolean().default(false),
enable_filter: Joi.boolean().default(false),
tenants: Joi.object().keys({
enable_private: Joi.boolean().default(true),
enable_global: Joi.boolean().default(true),
......
......@@ -81,7 +81,7 @@ module.exports = function (pluginRoot, server, kbnServer, APP_ROOT, API_ROOT) {
if (error instanceof AuthenticationError) {
return reply(Boom.unauthorized(error.message));
} else {
return reply(Boom.badImplementation());
return reply(Boom.badImplementation(error.message));
}
}
}
......
......@@ -14,6 +14,7 @@
limitations under the License.
*/
import _ from 'lodash';
import SearchGuardPlugin from './searchguard_plugin';
import AuthenticationError from '../auth/authentication_error';
import User from '../auth/user';
......@@ -42,9 +43,9 @@ export default class SearchGuardBackend {
return new User(credentials.username, credentials, credentials, response.sg_roles, response.sg_tenants);
} catch(error) {
if (error.status == 401) {
throw new AuthenticationError();
throw new AuthenticationError("Invalid username or password");
} else {
throw error;
throw new Error(error.message);
}
}
}
......@@ -113,7 +114,7 @@ export default class SearchGuardBackend {
// sanity check
if (!globalEnabled && !privateEnabled && _.isEmpty(tenantsCopy)) {
throw new AuthenticationError("No tenant available.");
return null;
}
// get users preferred tenant
var prefs = request.state.searchguard_preferences;
......@@ -143,6 +144,6 @@ export default class SearchGuardBackend {
// this point can be reached if global and private are disabled,
// and the preferred tenant is not accessible anymore.
throw new AuthenticationError("No tenant available, preferred tenant has probably been removed.");
}
}
{
"name": "searchguard",
"version": "5.3.0",
"version": "5.2.2",
"description": "Search Guard features for kibana",
"main": "index.js",
"homepage": "https://floragunn.com",
......
......@@ -14,7 +14,6 @@
<input type="text" class="form-control kuiTextInput" id="username" name="username" placeholder="Username"
ng-model="ui.credentials.username" required/>
</div>
<hr class="guideBreak">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-lock"></i></div>
<input type="password" class="form-control kuiTextInput" id="password" name="password" placeholder="Password"
......
......@@ -16,6 +16,7 @@
import chrome from 'ui/chrome';
import {parse} from 'url';
import _ from 'lodash';
export default function LoginController(kbnUrl, $scope, $http, $window) {
......@@ -81,11 +82,7 @@ export default function LoginController(kbnUrl, $scope, $http, $window) {
},
(error) => {
if (error.status && error.status === 401) {
this.errorMessage = 'Invalid username or password, please try again';
} else {
this.errorMessage = 'An error occurred while checking your credentials, make sure your have an Elasticsearch cluster secured by Search Guard running.';
}
this.errorMessage = "Invalid username or password.";
}
);
};
......
......@@ -2,22 +2,49 @@
<div class="kuiLocalNav">
<div class="kuiLocalNavRow">
</div>
<div class="kuiLocalNavRow kuiLocalNavRow--secondary">
<div data-transclude-slot="bottomRow" class="kuiLocalTabs">
<span class="kuiLocalTab">
<div class="kuiLocalNavRow__section">
<div class="kuiLocalTitle">
Select Tenant
</span>
<br />
</div>
</div>
<div class="kuiLocalNavRow__section">
<div class="kuiLocalMenu">
<div class="kuiLocalMenuItem">
<div class="kuiLocalMenuItem__icon kuiIcon fa-user"></div>
Logged in as: {{ctrl.username}}
</div>
<div class="kuiLocalMenuItem" ng-show="ctrl.showroles">
<div class="kuiLocalMenuItem__icon kuiIcon fa-group"></div>
Roles: {{ctrl.roles}}
</div>
</div>
</div>
</div>
<div class="kuiLocalNavRow kuiLocalNavRow--secondary" ng-show="ctrl.showfilter">
<div class="kuiLocalSearch">
<input
class="kuiLocalSearchInput"
type="text"
placeholder="Filter..."
autocomplete="off"
ng-model="ctrl.tenantSearch"
>
<button class="kuiLocalSearchButton">
<span class="kuiIcon fa-search"></span>
</button>
</div>
</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>
<h2 class="text-center" ng-bind="ctrl.tenantLabel"></h2>
<h5 class="error-message" ng-if="ctrl.errorMessage" ng-bind="ctrl.errorMessage"></h5>
</div>
</div>
......@@ -29,11 +56,13 @@
<tr>
<th class="kuiTableHeaderCell">Name</th>
<th class="kuiTableHeaderCell">Permissions</th>
<th class="kuiTableHeaderCell kuiTableHeaderCell--alignRight">Action</th>
<th class="kuiTableHeaderCell"></th>
<th class="kuiTableHeaderCell"></th>
<th class="kuiTableHeaderCell"></th>
</tr>
</thead>
<tbody>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ''}" ng-show="ctrl.globalEnabled">
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ''}" ng-show="ctrl.globalEnabled && (ctrl.tenantSearch == '' || 'global'.startsWith(ctrl.tenantSearch.toLowerCase()))">
<td class="kuiTableRowCell">
{{ctrl.GLOBAL_USER_LABEL}}
</td>
......@@ -41,6 +70,16 @@
<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 == tenantkey"
ng-click="ctrl.selectTenant(ctrl.GLOBAL_USER_LABEL, ctrl.GLOBAL_USER_VALUE, 'dash')">Show Dashboards
</button>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(ctrl.GLOBAL_USER_LABEL, ctrl.GLOBAL_USER_VALUE, 'vis')">Show Visualizations
</button>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == ''"
ng-show="ctrl.currentTenant != ctrl.GLOBAL_USER_VALUE"
......@@ -48,21 +87,30 @@
</button>
</td>
</tr>
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE}" ng-show="ctrl.privateEnabled">
<tr class="kuiTableRow" ng-class="{'selected': ctrl.currentTenant == ctrl.PRIVATE_USER_VALUE}" ng-show="ctrl.privateEnabled && (ctrl.tenantSearch == '' || 'private'.startsWith(ctrl.tenantSearch.toLowerCase()))">
<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 == tenantkey"
ng-click="ctrl.selectTenant(ctrl.PRIVATE_USER_LABEL, ctrl.PRIVATE_USER_VALUE, 'dash')">Show Dashboards
</button>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(ctrl.PRIVATE_USER_LABEL, ctrl.PRIVATE_USER_VALUE, 'vis')">Show Visualizations
</button>
</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}">
<tr class="kuiTableRow" ng-show="ctrl.tenantSearch == '' || tenantkey.toLowerCase().startsWith(ctrl.tenantSearch.toLowerCase())" ng-repeat="tenantkey in ctrl.tenantkeys" ng-class="{'selected': tenantkey == ctrl.currentTenant}">
<td class="kuiTableRowCell">
{{tenantkey}}
</td>
......@@ -70,6 +118,16 @@
<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, 'dash')">Show Dashboards
</button>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(tenantkey, tenantkey, 'vis')">Show Visualizations
</button>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(tenantkey, tenantkey)">Select
......@@ -81,4 +139,4 @@
</div>
</div>
</div>
</div>
\ No newline at end of file
</div>
......@@ -34,7 +34,7 @@ uiRoutes
uiModules
.get('app/searchguard-multitenancy')
.controller('searchguardMultitenancyController', function ($http) {
.controller('searchguardMultitenancyController', function ($http, $window) {
var APP_ROOT = `${chrome.getBasePath()}/searchguard`;
var API_ROOT = `${APP_ROOT}/api/v1`;
......@@ -46,6 +46,8 @@ uiModules
this.privateEnabled = chrome.getInjected("multitenancy.tenants.enable_private");
this.globalEnabled = chrome.getInjected("multitenancy.tenants.enable_global");
this.showfilter = chrome.getInjected("multitenancy.enable_filter");
this.showroles = chrome.getInjected("multitenancy.show_roles");
this.GLOBAL_USER_LABEL = "Global";
this.GLOBAL_USER_VALUE = null;
......@@ -53,6 +55,8 @@ uiModules
this.PRIVATE_USER_LABEL = "Private";
this.PRIVATE_USER_VALUE = "__user__";
this.currentTenant = null;
this.tenantSearch = "";
this.roles = "";
$http.get(`${API_ROOT}/multitenancy/info`)
.then(
......@@ -105,6 +109,7 @@ uiModules
this.tenants = allTenants;
this.tenantkeys = tenantkeys;
this.roles = response.data.sg_roles.join(", ");
$http.get(`${API_ROOT}/multitenancy/tenant`)
.then(
......@@ -119,7 +124,7 @@ uiModules
);
this.selectTenant = function (tenantLabel, tenant) {
this.selectTenant = function (tenantLabel, tenant, redirect) {
$http.post(`${API_ROOT}/multitenancy/tenant`, {tenant: tenant, username: this.username})
.then(
(response) => {
......@@ -131,7 +136,16 @@ 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");
if(redirect) {
if (redirect == 'vis') {
$window.location.href = chrome.getNavLinkById("kibana:visualize").url;
}
if (redirect == 'dash') {
$window.location.href = chrome.getNavLinkById("kibana:dashboard").url;
}
} else {
notify.info("Tenant changed");
}
},
(error) => notify.error(error)
);
......
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