fix: Previously provisioned JWT's should be revoked on signout (#3639)
* feat: auth.delete endpoint * test
This commit is contained in:
@@ -253,6 +253,12 @@ export default class AuthStore {
|
|||||||
|
|
||||||
@action
|
@action
|
||||||
logout = async (savePath = false) => {
|
logout = async (savePath = false) => {
|
||||||
|
if (!this.token) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.post(`/auth.delete`);
|
||||||
|
|
||||||
// remove user and team from localStorage
|
// remove user and team from localStorage
|
||||||
Storage.set(AUTH_STORE, {
|
Storage.set(AUTH_STORE, {
|
||||||
user: null,
|
user: null,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SaveOptions } from "sequelize";
|
import type { SaveOptions } from "sequelize";
|
||||||
import {
|
import {
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
AfterSave,
|
AfterSave,
|
||||||
@@ -159,6 +159,7 @@ class Event extends IdModel {
|
|||||||
"users.create",
|
"users.create",
|
||||||
"users.update",
|
"users.update",
|
||||||
"users.signin",
|
"users.signin",
|
||||||
|
"users.signout",
|
||||||
"users.promote",
|
"users.promote",
|
||||||
"users.demote",
|
"users.demote",
|
||||||
"users.invite",
|
"users.invite",
|
||||||
|
|||||||
@@ -48,6 +48,30 @@ describe("#auth.info", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#auth.delete", () => {
|
||||||
|
it("should make the access token unusable", async () => {
|
||||||
|
const user = await buildUser();
|
||||||
|
const res = await server.post("/api/auth.delete", {
|
||||||
|
body: {
|
||||||
|
token: user.getJwtToken(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status).toEqual(200);
|
||||||
|
|
||||||
|
const res2 = await server.post("/api/auth.info", {
|
||||||
|
body: {
|
||||||
|
token: user.getJwtToken(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res2.status).toEqual(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should require authentication", async () => {
|
||||||
|
const res = await server.post("/api/auth.delete");
|
||||||
|
expect(res.status).toEqual(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#auth.config", () => {
|
describe("#auth.config", () => {
|
||||||
it("should return available SSO providers", async () => {
|
it("should return available SSO providers", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
env.DEPLOYMENT = "hosted";
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ import invariant from "invariant";
|
|||||||
import Router from "koa-router";
|
import Router from "koa-router";
|
||||||
import { find } from "lodash";
|
import { find } from "lodash";
|
||||||
import { parseDomain } from "@shared/utils/domains";
|
import { parseDomain } from "@shared/utils/domains";
|
||||||
|
import { sequelize } from "@server/database/sequelize";
|
||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
import auth from "@server/middlewares/authentication";
|
import auth from "@server/middlewares/authentication";
|
||||||
import { Team, TeamDomain } from "@server/models";
|
import { Event, Team, TeamDomain } from "@server/models";
|
||||||
import { presentUser, presentTeam, presentPolicies } from "@server/presenters";
|
import { presentUser, presentTeam, presentPolicies } from "@server/presenters";
|
||||||
import ValidateSSOAccessTask from "@server/queues/tasks/ValidateSSOAccessTask";
|
import ValidateSSOAccessTask from "@server/queues/tasks/ValidateSSOAccessTask";
|
||||||
import providers from "../auth/providers";
|
import providers from "../auth/providers";
|
||||||
@@ -125,4 +126,31 @@ router.post("auth.info", auth(), async (ctx) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post("auth.delete", auth(), async (ctx) => {
|
||||||
|
const { user } = ctx.state;
|
||||||
|
|
||||||
|
await sequelize.transaction(async (transaction) => {
|
||||||
|
await user.rotateJwtSecret({ transaction });
|
||||||
|
await Event.create(
|
||||||
|
{
|
||||||
|
name: "users.signout",
|
||||||
|
actorId: user.id,
|
||||||
|
userId: user.id,
|
||||||
|
teamId: user.teamId,
|
||||||
|
data: {
|
||||||
|
name: user.name,
|
||||||
|
},
|
||||||
|
ip: ctx.request.ip,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
transaction,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export type UserEvent =
|
|||||||
| {
|
| {
|
||||||
name: "users.create" // eslint-disable-line
|
name: "users.create" // eslint-disable-line
|
||||||
| "users.signin"
|
| "users.signin"
|
||||||
|
| "users.signout"
|
||||||
| "users.update"
|
| "users.update"
|
||||||
| "users.suspend"
|
| "users.suspend"
|
||||||
| "users.activate"
|
| "users.activate"
|
||||||
|
|||||||
Reference in New Issue
Block a user