Commit 4b5a5912 authored by Jochen Kressin's avatar Jochen Kressin
Browse files

added jwt query param support

parent 315135dd
......@@ -44,6 +44,11 @@ export default function (kibana) {
enable_private: Joi.boolean().default(true),
enable_global: Joi.boolean().default(true),
}).default(),
}).default(),
jwt: Joi.object().keys({
enabled: Joi.boolean().default(false),
url_param: Joi.string().default('authorization'),
header: Joi.string().default('Authorization')
}).default()
}).default();
return obj;
......@@ -177,12 +182,31 @@ export default function (kibana) {
password: config.get("searchguard.cookie.password")
});
this.status.yellow("Search Guard multitenancy enabled");
} else {
this.status.yellow("Search Guard multitenancy disabled");
}
if(config.get('searchguard.jwt.enabled')) {
require('./lib/jwt/headers')(pluginRoot, server, this, APP_ROOT, API_ROOT);
server.state('searchguard_jwt', {
ttl: null,
path: '/',
isSecure: false,
isHttpOnly: false,
clearInvalid: true, // remove invalid cookies
strictHeader: true, // don't allow violations of RFC 6265
encoding: 'iron',
password: config.get("searchguard.cookie.password")
});
this.status.yellow("Search Guard copy JWT params enabled");
} else {
this.status.yellow("Search Guard copy JWT params disabled");
}
this.status.green('Search Guard plugin initialised.');
}
......
......@@ -144,7 +144,32 @@ export default class SearchGuardBackend {
// this point can be reached if global and private are disabled,
// and the preferred tenant is not accessible anymore.
}
validateTenant(username, requestedTenant, tenants, globalEnabled, privateEnabled) {
// delete user from tenants first to check if we have a tenant to choose from at all
// keep original preferences untouched, we need the original values again
// http://stackoverflow.com/questions/728360/how-do-i-correctly-clone-a-javascript-object
var tenantsCopy = JSON.parse(JSON.stringify(tenants));
delete tenantsCopy[username];
// sanity check
if (!globalEnabled && !privateEnabled && _.isEmpty(tenantsCopy)) {
return null;
}
if (tenants[requestedTenant]) {
return requestedTenant;
}
if (requestedTenant == "private" && tenants[username] && privateEnabled) {
return "__user__";
}
if (requestedTenant == "global" && globalEnabled) {
return "";
}
return null;
}
}
......@@ -16,6 +16,7 @@
import Boom from 'boom';
import {assign} from 'lodash';
const querystring = require('querystring')
export default function (pluginRoot, server, APP_ROOT, API_ROOT) {
const config = server.config();
......@@ -38,7 +39,7 @@ export default function (pluginRoot, server, APP_ROOT, API_ROOT) {
if (request.url.path.indexOf(API_ROOT) === 0 || request.method !== 'get') {
return reply(Boom.forbidden(error));
} else {
const nextUrl = encodeURIComponent(request.path);
const nextUrl = encodeURIComponent(request.url.path);
return reply.redirect(`${basePath}${APP_ROOT}/login?nextUrl=${nextUrl}`);
}
}
......
/**
* Copyright 2017 floragunn GmbH
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 {assign} from 'lodash';
export default function (pluginRoot, server, APP_ROOT, API_ROOT) {
const config = server.config();
const basePath = config.get('server.basePath');
const backend = server.plugins.searchguard.getSearchGuardBackend();
const urlparamname = server.config().get('searchguard.jwt.url_param');
const headername = server.config().get('searchguard.jwt.header');
server.ext('onPostAuth', async function (request, next) {
var jwtBearer = request.state.searchguard_jwt;
var jwtAuthParam = request.query[urlparamname];
if(jwtAuthParam != null) {
jwtBearer = jwtAuthParam;
next.state('searchguard_jwt', jwtBearer);
}
if (jwtBearer != null) {
var headerValue = "Bearer " + jwtBearer;
var headers = {};
headers[headername] = headerValue;
assign(request.headers, headers);
}
return next.continue();
});
}
......@@ -20,20 +20,25 @@ export default function (pluginRoot, server, APP_ROOT, API_ROOT) {
const config = server.config();
const basePath = config.get('server.basePath');
const global_enabled = config.get("searchguard.multitenancy.tenants.enable_global");
const private_enabled = config.get("searchguard.multitenancy.tenants.enable_private");
const backend = server.plugins.searchguard.getSearchGuardBackend();
server.ext('onPostAuth', async function (request, next) {
// default is the tenant stored in the tenants cookie
var selectedTenant = request.state.searchguard_tenant;
// check for tenant in request
if (request.query && request.query.sg_tenant) {
// check whether the tenant in the request param is contained in the
// list of valid tenants from the backend
let requestedTenant = request.query.sg_tenant;
let response = await backend.authinfo(request.headers);
selectedTenant = backend.validateTenant(response.user_name, requestedTenant, response.sg_tenants, global_enabled, private_enabled);
if(response.sg_tenants && response.sg_tenants[requestedTenant]) {
selectedTenant = requestedTenant;
if(selectedTenant != null) {
// save validated tenant as preference
backend.updateAndGetTenantPreferences(request, response.user_name, selectedTenant);
next.state('searchguard_tenant', selectedTenant);
}
}
......
......@@ -19,9 +19,9 @@
<input type="password" class="form-control kuiTextInput" id="password" name="password" placeholder="Password"
ng-model="ui.credentials.password" required/>
</div>
<button type="submit" class="btn btn-default btn-login" style="{{ui.buttonstyle}}">Log in</button>
<button id="login" type="submit" class="btn btn-default btn-login" style="{{ui.buttonstyle}}">Log in</button>
</form>
<p class="error-message" ng-if="ui.errorMessage">{{ ui.errorMessage }}</p>
<p class="error-message" id="errorMessage" ng-if="ui.errorMessage">{{ ui.errorMessage }}</p>
</div>
......@@ -74,12 +74,12 @@
</div>
<div class="container">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12">
<div class="page-header">
<h2 class="text-center" ng-bind="ctrl.tenantLabel"></h2>
<h5 class="error-message" ng-if="ctrl.errorMessage" ng-bind="ctrl.errorMessage"></h5>
<h2 class="text-center" ng-bind="ctrl.tenantLabel" id="tenantLabel"></h2>
<h5 class="error-message" ng-if="ctrl.errorMessage" ng-bind="ctrl.errorMessage" id="tenantErrorMessage"></h5>
</div>
</div>
</div>
......@@ -105,17 +105,17 @@
<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"
<button id="show_dashboard_global" 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"
<button id="show_visualization_global" 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 == ''"
<button id="select_global" 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>
......@@ -129,17 +129,17 @@
<div>read/write</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
<button id="show_dashboard_private" 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"
<button id="show_visualization_private" 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"
<button id="select_private" 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>
......@@ -153,17 +153,17 @@
<div ng-if="!ctrl.tenants[tenantkey]">read only</div>
</td>
<td class="actions kuiTableRowCell">
<button class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
<button id="show_dashboard_{{tenantkey}}" 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"
<button id="show_visualization_{{tenantkey}}" 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"
<button id="select_{{tenantkey}}" class="kuiButton kuiButton--primary" ng-disabled="ctrl.currentTenant == tenantkey"
ng-click="ctrl.selectTenant(tenantkey, tenantkey)">Select
</button>
</td>
......
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