Added impersonation tokens for admins

Closes #32
This commit is contained in:
Mutzi 2022-09-06 15:33:54 +02:00
parent 24bf069f49
commit 05c207daae
4 changed files with 35 additions and 0 deletions

View File

@ -92,5 +92,19 @@ namespace api {
void admin::is_admin(req_type, cbk_type cbk) { void admin::is_admin(req_type, cbk_type cbk) {
cbk(dto::Responses::get_success_res()); cbk(dto::Responses::get_success_res());
} }
void admin::get_token(req_type, cbk_type cbk, uint64_t user) {
db::MapperUser user_mapper(drogon::app().getDbClient());
try {
const auto &db_user = user_mapper.findByPrimaryKey(user);
const std::string &token = auth::get_token(db_user);
cbk(dto::Responses::get_login_res(token));
} catch (const std::exception&) {
cbk(dto::Responses::get_badreq_res("Bad user"));
}
}
} }
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -25,6 +25,7 @@ public:
METHOD_ADD(admin::delete_user, "/delete", drogon::Post, "Login", "Admin"); METHOD_ADD(admin::delete_user, "/delete", drogon::Post, "Login", "Admin");
METHOD_ADD(admin::disable_2fa, "/disable_2fa", drogon::Post, "Login", "Admin"); METHOD_ADD(admin::disable_2fa, "/disable_2fa", drogon::Post, "Login", "Admin");
METHOD_ADD(admin::is_admin, "/is_admin", drogon::Get, "Login", "Admin"); METHOD_ADD(admin::is_admin, "/is_admin", drogon::Get, "Login", "Admin");
METHOD_ADD(admin::get_token, "/get_token/{}", drogon::Get, "Login", "Admin");
METHOD_LIST_END METHOD_LIST_END
void users(req_type, cbk_type); void users(req_type, cbk_type);
@ -33,6 +34,7 @@ public:
void delete_user(req_type, cbk_type); void delete_user(req_type, cbk_type);
void disable_2fa(req_type, cbk_type); void disable_2fa(req_type, cbk_type);
void is_admin(req_type, cbk_type); void is_admin(req_type, cbk_type);
void get_token(req_type, cbk_type, uint64_t user);
}; };
class auth : public drogon::HttpController<auth> { class auth : public drogon::HttpController<auth> {

View File

@ -54,5 +54,11 @@ export const disable_tfa = (
token token
); );
export const impersonate = (
user: number,
token: string
): Promise<Responses.Login | Responses.Error> =>
get_token(`/api/admin/get_token/${user}`, token);
export const is_admin = async (token: string): Promise<boolean> => export const is_admin = async (token: string): Promise<boolean> =>
!isErrorResponse(await get_token('/api/admin/is_admin', token)); !isErrorResponse(await get_token('/api/admin/is_admin', token));

View File

@ -48,6 +48,16 @@ const setRole = loadingMsgWrapper(
} }
); );
const impersonate = loadingMsgWrapper(message, async (user: number) => {
const token = await check_token(jwt);
if (!token) return;
const res = await Admin.impersonate(user, token);
if (isErrorResponse(res)) return console.error(res.message);
jwt.setToken(res.jwt);
await router.push({ path: '/' });
});
const action = ( const action = (
func: ( func: (
user: number, user: number,
@ -122,6 +132,9 @@ const columns: DataTableColumn<Responses.GetUsersEntry>[] = [
render(user) { render(user) {
return ( return (
<NButtonGroup> <NButtonGroup>
<NButton onClick={() => impersonate(user.id)}>
Impersonate
</NButton>
<NButton onClick={() => logoutUser(user.id)}> <NButton onClick={() => logoutUser(user.id)}>
Logout all Logout all
</NButton> </NButton>