Commit 40f95a95 by Shavonn Brown Committed by GitHub

16223 user auth token list and revoke (#17434)

* Start user auth token list on user profile (#16223)

* Now session found and first, better os regex (#16223)

* Revoke for user and admin user token manage (#16223)

* Tidying and styling (#16223)

* Tidying and styling (#16223)

* Update to use #16222 (#16223)

* Update for changes to 16222

* update per api issue
parent a20309d7
......@@ -126,7 +126,7 @@ export class SharedPreferences extends PureComponent<Props, State> {
getOptionLabel={i => i.title}
onChange={(dashboard: DashboardSearchHit) => this.onHomeDashboardChanged(dashboard.id)}
options={dashboards}
placeholder="Chose default dashboard"
placeholder="Choose default dashboard"
width={20}
/>
</div>
......
import _ from 'lodash';
import { dateTime } from '@grafana/ui';
import { BackendSrv } from 'app/core/services/backend_srv';
import { NavModelSrv } from 'app/core/core';
import { User } from 'app/core/services/context_srv';
import { UserSession } from 'app/types';
export default class AdminEditUserCtrl {
/** @ngInject */
constructor($scope: any, $routeParams: any, backendSrv: BackendSrv, $location: any, navModelSrv: NavModelSrv) {
$scope.user = {};
$scope.sessions = [];
$scope.newOrg = { name: '', role: 'Editor' };
$scope.permissions = {};
$scope.navModel = navModelSrv.getNav('admin', 'global-users', 0);
......@@ -14,6 +17,7 @@ export default class AdminEditUserCtrl {
$scope.init = () => {
if ($routeParams.id) {
$scope.getUser($routeParams.id);
$scope.getUserSessions($routeParams.id);
$scope.getUserOrgs($routeParams.id);
}
};
......@@ -26,6 +30,48 @@ export default class AdminEditUserCtrl {
});
};
$scope.getUserSessions = (id: number) => {
backendSrv.get('/api/admin/users/' + id + '/auth-tokens').then((sessions: UserSession[]) => {
sessions.reverse();
$scope.sessions = sessions.map((session: UserSession) => {
return {
id: session.id,
isActive: session.isActive,
seenAt: dateTime(session.seenAt).fromNow(),
createdAt: dateTime(session.createdAt).format('MMMM DD, YYYY'),
clientIp: session.clientIp,
browser: session.browser,
browserVersion: session.browserVersion,
os: session.os,
osVersion: session.osVersion,
device: session.device,
};
});
});
};
$scope.revokeUserSession = (tokenId: number) => {
backendSrv
.post('/api/admin/users/' + $scope.user_id + '/revoke-auth-token', {
authTokenId: tokenId,
})
.then(() => {
$scope.sessions = $scope.sessions.filter((session: UserSession) => {
if (session.id === tokenId) {
return false;
}
return true;
});
});
};
$scope.revokeAllUserSessions = (tokenId: number) => {
backendSrv.post('/api/admin/users/' + $scope.user_id + '/logout').then(() => {
$scope.sessions = [];
});
};
$scope.setPassword = () => {
if (!$scope.passwordForm.$valid) {
return;
......
......@@ -70,6 +70,7 @@
</div>
</form>
<div class="gf-form-group">
<table class="filter-table">
<thead>
<tr>
......@@ -97,5 +98,38 @@
</td>
</tr>
</table>
</div>
<h3 class="page-heading">Sessions</h3>
<div class="gf-form-group">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Last seen</th>
<th>Logged on</th>
<th>IP address</th>
<th>Browser &amp; OS</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="session in sessions">
<td ng-if="session.isActive">Now</td>
<td ng-if="!session.isActive">{{session.seenAt}}</td>
<td>{{session.createdAt}}</td>
<td>{{session.clientIp}}</td>
<td>{{session.browser}} on {{session.os}} {{session.osVersion}}</td>
<td>
<button class="btn btn-danger btn-small" ng-click="revokeUserSession(session.id)">
<i class="fa fa-power-off"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<button ng-if="sessions.length" class="btn btn-danger" ng-click="revokeAllUserSessions()">Logout user from all devices</button>
</div>
......@@ -13,9 +13,7 @@ function convertToAlertRule(dto: AlertRuleDTO, state: string): AlertRule {
stateText: stateModel.text,
stateIcon: stateModel.iconClass,
stateClass: stateModel.stateClass,
stateAge: dateTime(dto.newStateDate)
.fromNow()
.replace(' ago', ''),
stateAge: dateTime(dto.newStateDate).fromNow(true),
};
if (rule.state !== 'paused') {
......
import config from 'app/core/config';
import { coreModule } from 'app/core/core';
import { dateTime } from '@grafana/ui';
import { UserSession } from 'app/types';
export class ProfileCtrl {
user: any;
oldTheme: any;
teams: any = [];
orgs: any = [];
sessions: object[] = [];
userForm: any;
showTeamsList = false;
showOrgsList = false;
......@@ -15,6 +18,7 @@ export class ProfileCtrl {
/** @ngInject */
constructor(private backendSrv, private contextSrv, private $location, navModelSrv) {
this.getUser();
this.getUserSessions();
this.getUserTeams();
this.getUserOrgs();
this.navModel = navModelSrv.getNav('profile', 'profile-settings', 0);
......@@ -27,6 +31,52 @@ export class ProfileCtrl {
});
}
getUserSessions() {
this.backendSrv.get('/api/user/auth-tokens').then((sessions: UserSession[]) => {
sessions.reverse();
const found = sessions.findIndex((session: UserSession) => {
return session.isActive;
});
if (found) {
const now = sessions[found];
sessions.splice(found, found);
sessions.unshift(now);
}
this.sessions = sessions.map((session: UserSession) => {
return {
id: session.id,
isActive: session.isActive,
seenAt: dateTime(session.seenAt).fromNow(),
createdAt: dateTime(session.createdAt).format('MMMM DD, YYYY'),
clientIp: session.clientIp,
browser: session.browser,
browserVersion: session.browserVersion,
os: session.os,
osVersion: session.osVersion,
device: session.device,
};
});
});
}
revokeUserSession(tokenId: number) {
this.backendSrv
.post('/api/user/revoke-auth-token', {
authTokenId: tokenId,
})
.then(() => {
this.sessions = this.sessions.filter((session: UserSession) => {
if (session.id === tokenId) {
return false;
}
return true;
});
});
}
getUserTeams() {
this.backendSrv.get('/api/user/teams').then(teams => {
this.teams = teams;
......
......@@ -74,3 +74,32 @@
</tbody>
</table>
</div>
<h3 class="page-heading">Sessions</h3>
<div class="gf-form-group">
<table class="filter-table form-inline">
<thead>
<tr>
<th>Last seen</th>
<th>Logged on</th>
<th>IP address</th>
<th>Browser &amp; OS</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="session in ctrl.sessions">
<td ng-if="session.isActive">Now</td>
<td ng-if="!session.isActive">{{session.seenAt}}</td>
<td>{{session.createdAt}}</td>
<td>{{session.clientIp}}</td>
<td>{{session.browser}} on {{session.os}} {{session.osVersion}}</td>
<td>
<button class="btn btn-danger btn-small" ng-click="ctrl.revokeUserSession(session.id)">
<i class="fa fa-power-off"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
......@@ -48,3 +48,16 @@ export interface UserState {
orgId: number;
timeZone: string;
}
export interface UserSession {
id: number;
createdAt: string;
clientIp: string;
isActive: boolean;
seenAt: string;
browser: string;
browserVersion: string;
os: string;
osVersion: string;
device: string;
}
Markdown is supported
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