Skip to content

Commit

Permalink
Added feature to Log in as another user and log back out. Only availa…
Browse files Browse the repository at this point in the history
…ble for Admins.
  • Loading branch information
jc21 committed Jun 18, 2018
1 parent 5ada900 commit dc994e8
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 34 deletions.
28 changes: 27 additions & 1 deletion src/backend/internal/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module.exports = {
}, {
expiresIn: expiry.unix()
})
.then((signed) => {
.then(signed => {
return {
token: signed.token,
expires: expiry.toISOString()
Expand Down Expand Up @@ -136,5 +136,31 @@ module.exports = {
} else {
throw new error.AssertionFailedError('Existing token contained invalid user data');
}
},

/**
* @param {Object} user
* @returns {Promise}
*/
getTokenFromUser: user => {
let Token = new TokenModel();
let expiry = helpers.parseDatePeriod('1d');

return Token.create({
iss: 'api',
attrs: {
id: user.id
},
scope: ['user']
}, {
expiresIn: expiry.unix()
})
.then(signed => {
return {
token: signed.token,
expires: expiry.toISOString(),
user: user
};
});
}
};
17 changes: 16 additions & 1 deletion src/backend/internal/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ const internalUser = {

return query;
})
.then((row) => {
.then(row => {
if (row) {
return _.omit(row, omissions());
} else {
Expand Down Expand Up @@ -429,6 +429,21 @@ const internalUser = {
.then(() => {
return internalUser.get(access, {id: data.id, expand: ['services']});
});
},

/**
* @param {Access} access
* @param {Object} data
* @param {Integer} data.id
*/
loginAs: (access, data) => {
return access.can('users:loginas', data.id)
.then(() => {
return internalUser.get(access, data);
})
.then(user => {
return internalToken.getTokenFromUser(user);
});
}
};

Expand Down
7 changes: 7 additions & 0 deletions src/backend/lib/access/users-loginas.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"anyOf": [
{
"$ref": "roles#/definitions/admin"
}
]
}
26 changes: 26 additions & 0 deletions src/backend/routes/api/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,30 @@ router
.catch(next);
});

/**
* Specific user login as
*
* /api/users/123/login
*/
router
.route('/:user_id/login')
.options((req, res) => {
res.sendStatus(204);
})
.all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes

/**
* POST /api/users/123/login
*
* Log in as a user
*/
.post((req, res, next) => {
internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
.then(result => {
res.status(201)
.send(result);
})
.catch(next);
});

module.exports = router;
44 changes: 28 additions & 16 deletions src/frontend/js/app/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import $ from 'jquery';
import _ from 'underscore';
import Tokens from './tokens';

/**
* @param {String} message
Expand Down Expand Up @@ -39,7 +40,7 @@ function fetch (verb, path, data, options) {
return new Promise(function (resolve, reject) {
let api_url = '/api/';
let url = api_url + path;
let token = window.localStorage.getItem('juxtapose-token') || null;
let token = Tokens.getTopToken();

$.ajax({
url: url,
Expand All @@ -54,7 +55,7 @@ function fetch (verb, path, data, options) {
},

beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.setRequestHeader('Authorization', 'Bearer ' + (token ? token.t : null));
},

success: function (data, textStatus, response) {
Expand Down Expand Up @@ -115,16 +116,15 @@ module.exports = {
*/
login: function (identity, secret) {
return fetch('post', 'tokens', {identity: identity, secret: secret})
.then(function (response) {
.then(response => {
if (response.token) {
// Set storage token
window.localStorage.setItem('juxtapose-token', response.token);
Tokens.addToken(response.token);
return response.token;
} else {
window.localStorage.removeItem('juxtapose-token');
Tokens.clearTokens();
throw(new Error('No token returned'));
}

throw(new Error('No token returned'));
});
},

Expand All @@ -133,15 +133,14 @@ module.exports = {
*/
refresh: function () {
return fetch('get', 'tokens')
.then(function (response) {
.then(response => {
if (response.token) {
window.localStorage.setItem('juxtapose-token', response.token);
Tokens.setCurrentToken(response.token);
return response.token;
} else {
window.localStorage.removeItem('juxtapose-token');
Tokens.clearTokens();
throw(new Error('No token returned'));
}

throw(new Error('No token returned'));
});
}
},
Expand Down Expand Up @@ -215,6 +214,14 @@ module.exports = {
*/
saveServiceSettings: function (id, settings) {
return fetch('post', 'users/' + id + '/services', {settings: settings});
},

/**
* @param {Integer} id
* @returns {Promise}
*/
loginAs: function (id) {
return fetch('post', 'users/' + id + '/login');
}
},

Expand Down Expand Up @@ -345,17 +352,22 @@ module.exports = {
*
* @param {Integer} from_user_id
* @param {Integer} to_user_id
* @param {String} [service_type]
* @param {String} [in_service_type]
* @param {String} [out_service_type]
* @returns {Promise}
*/
copy: function (from_user_id, to_user_id, service_type) {
copy: function (from_user_id, to_user_id, in_service_type, out_service_type) {
let data = {
from: from_user_id,
to: to_user_id
};

if (service_type) {
data.service_type = service_type;
if (in_service_type) {
data.in_service_type = in_service_type;
}

if (out_service_type) {
data.out_service_type = out_service_type;
}

return fetch('post', 'rules/copy', data);
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/js/app/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import Backbone from 'backbone';

const Cache = require('./cache');
const Cache = require('./cache');
const Tokens = require('./tokens');

module.exports = {

Expand Down Expand Up @@ -477,7 +478,7 @@ module.exports = {
* Logout
*/
logout: function () {
window.localStorage.removeItem('juxtapose-token');
Tokens.dropTopToken();
this.navigate('/');
window.location = '/';
window.location.reload();
Expand Down
10 changes: 4 additions & 6 deletions src/frontend/js/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const Controller = require('./controller');
const Router = require('./router');
const UI = require('./ui/main');
const Api = require('./api');
const Tokens = require('./tokens');

const App = Mn.Application.extend({

Expand All @@ -27,11 +28,7 @@ const App = Mn.Application.extend({

// Check if token is coming through
if (this.getParam('token')) {
window.localStorage.setItem('juxtapose-token', this.getParam('token'));

if (this.getParam('expires')) {
window.localStorage.setItem('juxtapose-expires', this.getParam('expires'));
}
Tokens.addToken(this.getParam('token'))
}

// Check if we are still logged in by refreshing the token
Expand Down Expand Up @@ -126,8 +123,9 @@ const App = Mn.Application.extend({
*/
bootstrap: function () {
return Api.Users.getById('me', ['services'])
.then((response) => {
.then(response => {
Cache.User.set(response);
Tokens.setCurrentName(response.nickname || response.name);
});
},

Expand Down
Loading

0 comments on commit dc994e8

Please sign in to comment.