diff --git a/lib/api/status.js b/lib/api/status.js
index 56196114a07..b1a15952970 100644
--- a/lib/api/status.js
+++ b/lib/api/status.js
@@ -20,6 +20,10 @@ function configure (app, wares, env, ctx) {
var authToken = req.query.token || req.query.secret || '';
+ function getRemoteIP (req) {
+ return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
+ }
+
var date = new Date();
var info = { status: 'ok'
, name: app.get('name')
@@ -31,7 +35,7 @@ function configure (app, wares, env, ctx) {
, boluscalcEnabled: app.enabled('api') && env.settings.enable.indexOf('boluscalc') > -1
, settings: settings
, extendedSettings: extended
- , authorized: ctx.authorization.authorize(authToken)
+ , authorized: ctx.authorization.authorize(authToken, getRemoteIP(req))
, runtimeState: ctx.runtimeState
};
diff --git a/lib/api/verifyauth.js b/lib/api/verifyauth.js
index a4eb2edf4ee..849ce9bef9a 100644
--- a/lib/api/verifyauth.js
+++ b/lib/api/verifyauth.js
@@ -8,15 +8,24 @@ function configure (ctx) {
api.get('/verifyauth', function(req, res) {
ctx.authorization.resolveWithRequest(req, function resolved (err, result) {
-
// this is used to see if req has api-secret equivalent authorization
- var authorized = !err &&
- ctx.authorization.checkMultiple('*:*:create,update,delete', result.shiros) && //can write to everything
- ctx.authorization.checkMultiple('admin:*:*:*', result.shiros); //full admin permissions too
+ var canRead = !err &&
+ ctx.authorization.checkMultiple('*:*:read', result.shiros);
+ var canWrite = !err &&
+ ctx.authorization.checkMultiple('*:*:write', result.shiros);
+ var isAdmin = !err &&
+ ctx.authorization.checkMultiple('*:*:admin', result.shiros);
+ var authorized = canRead && !result.defaults;
+
var response = {
+ canRead,
+ canWrite,
+ isAdmin,
message: authorized ? 'OK' : 'UNAUTHORIZED',
- rolefound: result.subject ? 'FOUND' : 'NOTFOUND'
- }
+ rolefound: result.subject ? 'FOUND' : 'NOTFOUND',
+ permissions: result.defaults ? 'DEFAULT' : 'ROLE'
+ };
+
res.sendJSONStatus(res, consts.HTTP_OK, response);
});
diff --git a/lib/api3/security.js b/lib/api3/security.js
index 33099d88f12..1488a0ee3b8 100644
--- a/lib/api3/security.js
+++ b/lib/api3/security.js
@@ -9,6 +9,10 @@ const moment = require('moment')
;
+function getRemoteIP (req) {
+ return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
+}
+
/**
* Check if Date header in HTTP request (or 'now' query parameter) is present and valid (with error response sending)
*/
@@ -68,7 +72,7 @@ function authenticate (opCtx) {
opTools.sendJSONStatus(res, apiConst.HTTP.UNAUTHORIZED, apiConst.MSG.HTTP_401_MISSING_OR_BAD_TOKEN));
}
- ctx.authorization.resolve({ token }, function resolveFinish (err, result) {
+ ctx.authorization.resolve({ token, ip: getRemoteIP(req) }, function resolveFinish (err, result) {
if (err) {
return reject(
opTools.sendJSONStatus(res, apiConst.HTTP.UNAUTHORIZED, apiConst.MSG.HTTP_401_BAD_TOKEN));
diff --git a/lib/authorization/delaylist.js b/lib/authorization/delaylist.js
new file mode 100644
index 00000000000..cfc0509e6ab
--- /dev/null
+++ b/lib/authorization/delaylist.js
@@ -0,0 +1,58 @@
+'use strict';
+
+function init () {
+
+ const ipDelayList = {};
+
+ const DELAY_ON_FAIL = 5000;
+ const FAIL_AGE = 60000;
+
+ const sleep = require('util').promisify(setTimeout);
+
+ ipDelayList.addFailedRequest = function addFailedRequest (ip) {
+ const ipString = String(ip);
+ let entry = ipDelayList[ipString];
+ const now = Date.now();
+ if (!entry) {
+ ipDelayList[ipString] = now + DELAY_ON_FAIL;
+ return;
+ }
+ if (now >= entry) { entry = now; }
+ ipDelayList[ipString] = entry + DELAY_ON_FAIL;
+ };
+
+ ipDelayList.shouldDelayRequest = function shouldDelayRequest (ip) {
+ const ipString = String(ip);
+ const entry = ipDelayList[ipString];
+ let now = Date.now();
+ if (entry) {
+ if (now < entry) {
+ return entry - now;
+ }
+ }
+ return false;
+ };
+
+ ipDelayList.requestSucceeded = function requestSucceeded (ip) {
+ const ipString = String(ip);
+ if (ipDelayList[ipString]) {
+ delete ipDelayList[ipString];
+ }
+ };
+
+ // Clear items older than a minute
+
+ setTimeout(function clearList () {
+ for (var key in ipDelayList) {
+ if (ipDelayList.hasOwnProperty(key)) {
+ if (Date.now() > ipDelayList[key] + FAIL_AGE) {
+ delete ipDelayList[key];
+ }
+ }
+ }
+ }, 30000);
+
+ return ipDelayList;
+}
+
+module.exports = init;
diff --git a/lib/authorization/index.js b/lib/authorization/index.js
index b81578e0dca..0f5fe138287 100644
--- a/lib/authorization/index.js
+++ b/lib/authorization/index.js
@@ -1,96 +1,85 @@
'use strict';
-var _ = require('lodash');
-var jwt = require('jsonwebtoken');
-var shiroTrie = require('shiro-trie');
-
-var consts = require('./../constants');
-
-var log_green = '\x1B[32m';
-var log_red = '\x1b[31m';
-var log_reset = '\x1B[0m';
-var LOG_GRANTED = log_green + 'GRANTED: ' + log_reset;
-var LOG_DENIED = log_red + 'DENIED: ' + log_reset;
-
-function mkopts (opts) {
- var options = opts && !_.isEmpty(opts) ? opts : { };
- if (!options.redirectDeniedURL) {
- options.redirectDeniedURL = null;
- }
- return options;
-}
+const _ = require('lodash');
+const jwt = require('jsonwebtoken');
+const shiroTrie = require('shiro-trie');
+
+const ipdelaylist = require('./delaylist')();
+const consts = require('./../constants');
+
+const sleep = require('util').promisify(setTimeout);
+
+const addFailedRequest = ipdelaylist.addFailedRequest;
+const shouldDelayRequest = ipdelaylist.shouldDelayRequest;
+const requestSucceeded = ipdelaylist.requestSucceeded;
function getRemoteIP (req) {
return req.headers['x-forwarded-for'] || req.connection.remoteAddress;
}
function init (env, ctx) {
- var authorization = { };
+ var authorization = {};
var storage = authorization.storage = require('./storage')(env, ctx);
var defaultRoles = (env.settings.authDefaultRoles || '').split(/[, :]/);
- function extractToken (req) {
- var token;
- var authorization = req.header('Authorization');
+ /**
+ * Loads JWT from request
+ *
+ * @param {*} req
+ */
+ function extractJWTfromRequest (req) {
+
+ if (req.auth_token) return req.auth_token;
- if (authorization) {
- var parts = authorization.split(' ');
+ let token;
+
+ if (req.header('Authorization')) {
+ const parts = req.header('Authorization').split(' ');
if (parts.length === 2 && parts[0] === 'Bearer') {
token = parts[1];
}
}
- if (!token && req.auth_token) {
- token = req.auth_token;
- }
-
if (!token) {
- token = authorizeAccessToken(req);
- }
+ let accessToken = req.query.token;
+ if (!accessToken && req.body) {
+ if (_.isArray(req.body) && req.body.length > 0 && req.body[0].token) {
+ accessToken = req.body[0].token;
+ delete req.body[0].token;
+ } else if (req.body.token) {
+ accessToken = req.body.token;
+ delete req.body.token;
+ }
+ }
- if (token) {
- req.auth_token = token;
+ if (accessToken) {
+ // validate and parse the token
+ const authed = authorization.authorize(accessToken);
+ if (authed && authed.token) {
+ token = authed.token;
+ }
+ }
}
+ if (token) { req.auth_token = token; }
+
return token;
}
- authorization.extractToken = extractToken;
-
- function authorizeAccessToken (req) {
+ authorization.extractToken = extractJWTfromRequest;
- var accessToken = req.query.token;
-
- if (!accessToken && req.body) {
- if (_.isArray(req.body) && req.body.length > 0 && req.body[0].token) {
- accessToken = req.body[0].token;
- delete req.body[0].token;
- } else if (req.body.token) {
- accessToken = req.body.token;
- delete req.body.token;
- }
- }
+ /**
+ * Fetches the API_SECRET from the request
+ *
+ * @param {*} req Express request object
+ */
+ function apiSecretFromRequest (req) {
- var authToken = null;
+ if (req.api_secret) return req.api_secret;
- if (accessToken) {
- // make an auth token on the fly, based on an access token
- var authed = authorization.authorize(accessToken);
- if (authed && authed.token) {
- authToken = authed.token;
- }
- }
+ let secret = req.query && req.query.secret ? req.query.secret : req.header('api-secret');
- return authToken;
- }
-
- function adminSecretFromRequest (req) {
- var secret = req.query && req.query.secret ? req.query.secret : req.header('api-secret');
-
- if (!secret && req.api_secret) {
- //see if we already got the secret from the body, since it gets deleted
- secret = req.api_secret;
- } else if (!secret && req.body) {
+ if (!secret && req.body) {
// try to get the secret from the body, but don't leave it there
if (_.isArray(req.body) && req.body.length > 0 && req.body[0].secret) {
secret = req.body[0].secret;
@@ -101,71 +90,125 @@ function init (env, ctx) {
}
}
- if (secret) {
- // store the secret hash on the request since the req may get processed again
- req.api_secret = secret;
- }
-
+ // store the secret hash on the request since the req may get processed again
+ if (secret) { req.api_secret = secret; }
return secret;
}
- function authorizeAdminSecretWithRequest (req) {
- return authorizeAdminSecret(adminSecretFromRequest(req));
- }
-
function authorizeAdminSecret (secret) {
return (env.api_secret && env.api_secret.length > 12) ? (secret === env.api_secret) : false;
}
- authorization.seenPermissions = [ ];
+ authorization.seenPermissions = [];
- authorization.expandedPermissions = function expandedPermissions ( ) {
+ authorization.expandedPermissions = function expandedPermissions () {
var permissions = shiroTrie.new();
permissions.add(authorization.seenPermissions);
return permissions;
};
authorization.resolveWithRequest = function resolveWithRequest (req, callback) {
- authorization.resolve({
- api_secret: adminSecretFromRequest(req)
- , token: extractToken(req)
- }, callback);
+ const resolveData = {
+ api_secret: apiSecretFromRequest(req)
+ , token: extractJWTfromRequest(req)
+ , ip: getRemoteIP(req)
+ };
+ authorization.resolve(resolveData, callback);
};
- authorization.checkMultiple = function checkMultiple(permission, shiros) {
+ /**
+ * Check if the Apache Shiro-style permission object includes the permission.
+ *
+ * Returns a boolean true / false depending on if the permission is found.
+ *
+ * @param {*} permission Desired permission
+ * @param {*} shiros Shiros
+ */
+
+ authorization.checkMultiple = function checkMultiple (permission, shiros) {
var found = _.find(shiros, function checkEach (shiro) {
return shiro && shiro.check(permission);
});
return _.isObject(found);
};
- authorization.resolve = function resolve (data, callback) {
+ /**
+ * Resolve an API secret or token and return the permissions associated with
+ * the secret / token
+ *
+ * @param {*} data
+ * @param {*} callback
+ */
+ authorization.resolve = async function resolve (data, callback) {
+
+ if (!data.ip) {
+ console.error('Trying to authorize without IP information');
+ return callback(null, { shiros: [] });
+ }
+
+ data.api_secret = data.api_secret || null;
+
+ if (data.api_secret == 'null') { // TODO find what's sending this anomaly
+ data.api_secret = null;
+ }
- var defaultShiros = storage.rolesToShiros(defaultRoles);
+ const requestDelay = shouldDelayRequest(data.ip);
- if (storage.doesAccessTokenExist(data.api_secret)) {
- authorization.resolveAccessToken (data.api_secret, callback, defaultShiros);
- return;
+ if (requestDelay) {
+ await sleep(requestDelay);
}
- if (authorizeAdminSecret(data.api_secret)) {
+ const authAttempted = (data.api_secret || data.token) ? true : false;
+ const defaultShiros = storage.rolesToShiros(defaultRoles);
+
+ // If there is no token or secret, return default permissions
+ if (!authAttempted) {
+ const result = { shiros: defaultShiros, defaults: true };
+ if (callback) { callback(null, result); }
+ return result;
+ }
+
+ // Check for API_SECRET first as that allows bailing out fast
+
+ if (data.api_secret && authorizeAdminSecret(data.api_secret)) {
+ requestSucceeded(data.ip);
var admin = shiroTrie.new();
admin.add(['*']);
- return callback(null, { shiros: [ admin ] });
+ const result = { shiros: [admin] };
+ if (callback) { callback(null, result); }
+ return result;
}
- if (data.token) {
- jwt.verify(data.token, env.api_secret, function result(err, verified) {
- if (err) {
- return callback(err, { shiros: [ ] });
- } else {
- authorization.resolveAccessToken (verified.accessToken, callback, defaultShiros);
- }
- });
- } else {
- return callback(null, { shiros: defaultShiros });
+ // If we reach this point, we must be dealing with a role based token
+
+ let token = null;
+
+ // Tokens have to be well formed JWTs
+ try {
+ const verified = await jwt.verify(data.token, env.api_secret);
+ token = verified.accessToken;
+ } catch (err) {}
+
+ // Check if there's a token in the secret
+
+ if (!token && data.api_secret) {
+ if (storage.doesAccessTokenExist(data.api_secret)) {
+ token = data.api_secret;
+ }
}
+ if (token) {
+ requestSucceeded(data.ip);
+ const results = authorization.resolveAccessToken(token, null, defaultShiros);
+ if (callback) { callback(null, results); }
+ return results;
+ }
+
+ console.error('Resolving secret/token to permissions failed');
+ addFailedRequest(data.ip);
+ callback('All validation failed', {});
+ return {};
+
};
authorization.resolveAccessToken = function resolveAccessToken (accessToken, callback, defaultShiros) {
@@ -176,94 +219,67 @@ function init (env, ctx) {
let resolved = storage.resolveSubjectAndPermissions(accessToken);
if (!resolved || !resolved.subject) {
- return callback('Subject not found', null);
+ if (callback) { callback('Subject not found', null); }
+ return null;
}
let shiros = resolved.shiros.concat(defaultShiros);
- return callback(null, { shiros: shiros, subject: resolved.subject });
+ const result = { shiros, subject: resolved.subject };
+ if (callback) { callback(null, result); }
+ return result;
};
- authorization.isPermitted = function isPermitted (permission, opts) {
-
+ /**
+ * Check if the client has a permission execute an action,
+ * based on an API_SECRET or JWT in the request.
+ *
+ * Used to authorize API calls
+ *
+ * @param {*} permission Permission being checked
+ */
+ authorization.isPermitted = function isPermitted (permission) {
- mkopts(opts);
authorization.seenPermissions = _.chain(authorization.seenPermissions)
.push(permission)
.sort()
.uniq()
.value();
- function check(req, res, next) {
+ async function check (req, res, next) {
var remoteIP = getRemoteIP(req);
+ var secret = apiSecretFromRequest(req);
+ var token = extractJWTfromRequest(req);
- var secret = adminSecretFromRequest(req);
- var defaultShiros = storage.rolesToShiros(defaultRoles);
-
- if (storage.doesAccessTokenExist(secret)) {
- var resolved = storage.resolveSubjectAndPermissions (secret);
-
- if (authorization.checkMultiple(permission, resolved.shiros)) {
- console.log(LOG_GRANTED, remoteIP, resolved.accessToken , permission);
- next();
- } else if (authorization.checkMultiple(permission, defaultShiros)) {
- console.log(LOG_GRANTED, remoteIP, resolved.accessToken, permission, 'default');
- next( );
- } else {
- console.log(LOG_DENIED, remoteIP, resolved.accessToken, permission);
- res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
- }
- return;
- }
+ const data = { api_secret: secret, token, ip: remoteIP };
- if (authorizeAdminSecretWithRequest(req)) {
- console.log(LOG_GRANTED, remoteIP, 'api-secret', permission);
- next( );
- return;
- }
+ const permissions = await authorization.resolve(data);
+ const permitted = authorization.checkMultiple(permission, permissions.shiros);
- var token = extractToken(req);
-
- if (token) {
- jwt.verify(token, env.api_secret, function result(err, verified) {
- if (err) {
- console.info('Error verifying Authorized Token', err);
- res.status(consts.HTTP_UNAUTHORIZED).send('Unauthorized - Invalid/Missing');
- } else {
- var resolved = storage.resolveSubjectAndPermissions(verified.accessToken);
- if (authorization.checkMultiple(permission, resolved.shiros)) {
- console.log(LOG_GRANTED, remoteIP, verified.accessToken , permission);
- next();
- } else if (authorization.checkMultiple(permission, defaultShiros)) {
- console.log(LOG_GRANTED, remoteIP, verified.accessToken, permission, 'default');
- next( );
- } else {
- console.log(LOG_DENIED, remoteIP, verified.accessToken, permission);
- res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
- }
- }
- });
- } else {
- if (authorization.checkMultiple(permission, defaultShiros)) {
- console.log(LOG_GRANTED, remoteIP, 'no-token', permission, 'default');
- return next( );
- }
- console.log(LOG_DENIED, remoteIP, 'no-token', permission);
- res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
+ if (permitted) {
+ next();
+ return;
}
+ res.sendJSONStatus(res, consts.HTTP_UNAUTHORIZED, 'Unauthorized', 'Invalid/Missing');
}
return check;
+
};
+ /**
+ * Generates a JWT based on an access token / authorizes an existing token
+ *
+ * @param {*} accessToken token to be used for generating a JWT for the client
+ */
authorization.authorize = function authorize (accessToken) {
- var subject = storage.findSubject(accessToken);
+ var subject = storage.findSubject(accessToken);
var authorized = null;
if (subject) {
- var token = jwt.sign( { accessToken: subject.accessToken }, env.api_secret, { expiresIn: '1h' } );
+ var token = jwt.sign({ accessToken: subject.accessToken }, env.api_secret, { expiresIn: '1h' });
//decode so we can tell the client the issued and expired times
var decoded = jwt.decode(token);
@@ -271,10 +287,10 @@ function init (env, ctx) {
var roles = _.uniq(subject.roles.concat(defaultRoles));
authorized = {
- token: token
+ token
, sub: subject.name
- // not sending roles to client to prevent us from treating them as magic
- // instead group permissions by role so the we can create correct shiros on the client
+ // not sending roles to client to prevent us from treating them as magic
+ // instead group permissions by role so the we can create correct shiros on the client
, permissionGroups: _.map(roles, storage.roleToPermissions)
, iat: decoded.iat
, exp: decoded.exp
diff --git a/lib/hashauth.js b/lib/client/hashauth.js
similarity index 59%
rename from lib/hashauth.js
rename to lib/client/hashauth.js
index 8848ca08ef0..6a2def96b31 100644
--- a/lib/hashauth.js
+++ b/lib/client/hashauth.js
@@ -4,21 +4,22 @@ var crypto = require('crypto');
var Storages = require('js-storage');
var hashauth = {
- apisecret: ''
- , storeapisecret: false
- , apisecrethash: null
- , authenticated: false
- , initialized: false
- , tokenauthenticated: false
+ initialized: false
};
-hashauth.init = function init(client, $) {
+hashauth.init = function init (client, $) {
- if (hashauth.initialized) {
- return hashauth;
- }
+ hashauth.apisecret = '';
+ hashauth.storeapisecret = false;
+ hashauth.apisecrethash = null;
+ hashauth.authenticated = false;
+ hashauth.tokenauthenticated = false;
+ hashauth.hasReadPermission = false;
+ hashauth.isAdmin = false;
+ hashauth.hasWritePermission = false;
+ hashauth.permissionlevel = 'NONE';
- hashauth.verifyAuthentication = function verifyAuthentication(next) {
+ hashauth.verifyAuthentication = function verifyAuthentication (next) {
hashauth.authenticated = false;
$.ajax({
method: 'GET'
@@ -26,15 +27,22 @@ hashauth.init = function init(client, $) {
, headers: client.headers()
}).done(function verifysuccess (response) {
- if (response.message.rolefound == 'FOUND') {
+
+ var message = response.message;
+
+ if (message.canRead) { hashauth.hasReadPermission = true; }
+ if (message.canWrite) { hashauth.hasWritePermission = true; }
+ if (message.isAdmin) { hashauth.isAdmin = true; }
+ if (message.permissions) { hashauth.permissionlevel = message.permissions; }
+
+ if (message.rolefound == 'FOUND') {
hashauth.tokenauthenticated = true;
console.log('Token Authentication passed.');
- client.authorizeSocket();
next(true);
return;
}
- if (response.message.message === 'OK') {
+ if (message.message === 'OK') {
hashauth.authenticated = true;
console.log('Authentication passed.');
next(true);
@@ -42,10 +50,10 @@ hashauth.init = function init(client, $) {
}
console.log('Authentication failed.', response);
- hashauth.removeAuthentication();
- next(false);
- return;
-
+ hashauth.removeAuthentication();
+ next(false);
+ return;
+
}).fail(function verifyfail (err) {
console.log('Authentication failed.', err);
hashauth.removeAuthentication();
@@ -53,23 +61,23 @@ hashauth.init = function init(client, $) {
});
};
- hashauth.injectHtml = function injectHtml ( ) {
+ hashauth.injectHtml = function injectHtml () {
if (!hashauth.injectedHtml) {
$('#authentication_placeholder').html(hashauth.inlineCode());
hashauth.injectedHtml = true;
}
};
- hashauth.initAuthentication = function initAuthentication(next) {
+ hashauth.initAuthentication = function initAuthentication (next) {
hashauth.apisecrethash = hashauth.apisecrethash || Storages.localStorage.get('apisecrethash') || null;
- hashauth.verifyAuthentication(function () {
+ hashauth.verifyAuthentication(function() {
hashauth.injectHtml();
- if (next) { next( hashauth.isAuthenticated() ); }
+ if (next) { next(hashauth.isAuthenticated()); }
});
return hashauth;
};
- hashauth.removeAuthentication = function removeAuthentication(event) {
+ hashauth.removeAuthentication = function removeAuthentication (event) {
Storages.localStorage.remove('apisecrethash');
@@ -92,14 +100,14 @@ hashauth.init = function init(client, $) {
var translate = client.translate;
hashauth.injectHtml();
- var clientWidth = window.innerWidth
- || document.documentElement.clientWidth
- || document.body.clientWidth;
+ var clientWidth = window.innerWidth ||
+ document.documentElement.clientWidth ||
+ document.body.clientWidth;
clientWidth = Math.min(400, clientWidth);
- $( '#requestauthenticationdialog' ).dialog({
- width: clientWidth
+ $('#requestauthenticationdialog').dialog({
+ width: clientWidth
, height: 270
, closeText: ''
, buttons: [
@@ -115,7 +123,7 @@ hashauth.init = function init(client, $) {
} else {
client.afterAuth(true);
}
- $( dialog ).dialog( 'close' );
+ $(dialog).dialog('close');
} else {
$('#apisecret').val('').focus();
}
@@ -123,8 +131,8 @@ hashauth.init = function init(client, $) {
}
}
]
- , open: function open ( ) {
- $('#apisecret').off('keyup').on('keyup' ,function pressed (e) {
+ , open: function open () {
+ $('#apisecret').off('keyup').on('keyup', function pressed (e) {
if (e.keyCode === $.ui.keyCode.ENTER) {
$('#requestauthenticationdialog-btn').trigger('click');
}
@@ -140,7 +148,7 @@ hashauth.init = function init(client, $) {
return false;
};
- hashauth.processSecret = function processSecret(apisecret, storeapisecret, callback) {
+ hashauth.processSecret = function processSecret (apisecret, storeapisecret, callback) {
var translate = client.translate;
hashauth.apisecret = apisecret;
@@ -155,10 +163,10 @@ hashauth.init = function init(client, $) {
shasum.update(hashauth.apisecret);
hashauth.apisecrethash = shasum.digest('hex');
- hashauth.verifyAuthentication( function(isok) {
+ hashauth.verifyAuthentication(function(isok) {
if (isok) {
if (hashauth.storeapisecret) {
- Storages.localStorage.set('apisecrethash',hashauth.apisecrethash);
+ Storages.localStorage.set('apisecrethash', hashauth.apisecrethash);
// TODO show dialog first, then reload
if (hashauth.tokenauthenticated) client.browserUtils.reload();
}
@@ -176,43 +184,57 @@ hashauth.init = function init(client, $) {
}
};
- hashauth.inlineCode = function inlineCode() {
+ hashauth.inlineCode = function inlineCode () {
var translate = client.translate;
var status = null;
+ if (!hashauth.isAdmin) {
+ $('.needsadminaccess').hide();
+ } else {
+ $('.needsadminaccess').show();
+ }
+
+ if (client.updateAdminMenu) client.updateAdminMenu();
+
if (client.authorized || hashauth.tokenauthenticated) {
status = translate('Authorized by token');
if (client.authorized && client.authorized.sub) {
- status += '
' + client.authorized.sub + ': ' + client.authorized.permissionGroups.join(', ') + '';
+ status += '
' + translate('Auth role') + ': ' + client.authorized.sub;
+ if (hashauth.hasReadPermission) { status += '
' + translate('Data reads enabled'); }
+ if (hashauth.hasWritePermission) { status += '
' + translate('Data writes enabled'); }
+ if (!hashauth.hasWritePermission) { status += '
' + translate('Data writes not enabled'); }
}
- if (hashauth.apisecrethash)
- {
+ if (hashauth.apisecrethash) {
status += '
(' + translate('Remove stored token') + ')';
} else {
- status += '
(' + translate('view without token') + ')';
+ status += '
(' + translate('view without token') + ')';
}
} else if (hashauth.isAuthenticated()) {
- console.info('status isAuthenticated', hashauth);
status = translate('Admin authorized') + ' (' + translate('Remove') + ')';
} else {
- status = translate('Unauthorized') + ' (' + translate('Authenticate') + ')';
+ status = translate('Unauthorized') +
+ '
' +
+ translate('Reads enabled in default permissions') +
+ '
' +
+ ' (' +
+ translate('Authenticate') + ')';
}
var html =
- '