Skip to content

Commit b1aa2b7

Browse files
authored
Allow admins to delete a specific MFA method for a user (#2012)
1 parent 12affba commit b1aa2b7

4 files changed

Lines changed: 29 additions & 16 deletions

File tree

crates/defguard_core/src/handlers/auth.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,9 @@ pub async fn totp_disable(
675675
session: SessionInfo,
676676
context: ApiRequestContext,
677677
State(appstate): State<AppState>,
678+
username: Path<String>,
678679
) -> ApiResult {
679-
let mut user = session.user;
680+
let mut user = user_for_admin_or_self(&appstate.pool, &session, &username).await?;
680681
debug!("Disabling TOTP for user {}", user.username);
681682
user.disable_totp(&appstate.pool).await?;
682683
user.verify_mfa_state(&appstate.pool).await?;
@@ -840,8 +841,9 @@ pub async fn email_mfa_disable(
840841
session: SessionInfo,
841842
context: ApiRequestContext,
842843
State(appstate): State<AppState>,
844+
username: Path<String>,
843845
) -> ApiResult {
844-
let mut user = session.user;
846+
let mut user = user_for_admin_or_self(&appstate.pool, &session, &username).await?;
845847
debug!("Disabling email MFA for user {}", user.username);
846848
user.disable_email_mfa(&appstate.pool).await?;
847849
user.verify_mfa_state(&appstate.pool).await?;

crates/defguard_core/src/lib.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,12 @@ pub fn build_webapp(
244244
.route("/auth/webauthn/start", post(webauthn_start))
245245
.route("/auth/webauthn", post(webauthn_end))
246246
.route("/auth/totp/init", post(totp_secret))
247-
.route("/auth/totp", post(totp_enable).delete(totp_disable))
247+
.route("/auth/totp", post(totp_enable))
248248
.route("/auth/totp/verify", post(totp_code))
249249
.route("/auth/email/init", post(email_mfa_init))
250250
.route(
251251
"/auth/email",
252-
get(request_email_mfa_code)
253-
.post(email_mfa_enable)
254-
.delete(email_mfa_disable),
252+
get(request_email_mfa_code).post(email_mfa_enable),
255253
)
256254
.route("/auth/email/verify", post(email_mfa_code))
257255
.route("/auth/recovery", post(recovery_code))
@@ -269,6 +267,9 @@ pub fn build_webapp(
269267
.route("/user/change_password", put(change_self_password))
270268
.route("/user/{username}/password", put(change_password))
271269
.route("/user/{username}/reset_password", post(reset_password))
270+
// disable mfa
271+
.route("/user/{username}/email", delete(email_mfa_disable))
272+
.route("/user/{username}/totp", delete(totp_disable))
272273
// auth keys
273274
.route(
274275
"/user/{username}/auth_key",

web/src/pages/user-profile/UserProfilePage/tabs/ProfileDetailsTab/components/ProfileAuthCard/ProfileAuthCard.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ export const ProfileAuthCard = () => {
7878
});
7979

8080
const { mutate: mutateDisableEmailMfa } = useMutation({
81-
mutationFn: api.auth.mfa.email.disable,
81+
mutationFn: api.user.mfa.email.disable,
8282
meta: invalidateAfterMfaChange,
8383
});
8484

8585
const { mutate: mutateDisableTotp } = useMutation({
86-
mutationFn: api.auth.mfa.totp.disable,
86+
mutationFn: api.user.mfa.totp.disable,
8787
meta: invalidateAfterMfaChange,
8888
});
8989

@@ -99,7 +99,6 @@ export const ProfileAuthCard = () => {
9999
},
100100
meta: invalidateAfterMfaChange,
101101
});
102-
103102
const emailMenuItems = useMemo(() => {
104103
const items: MenuItemProps[] = [];
105104
if (!user.email_mfa_enabled) {
@@ -121,7 +120,7 @@ export const ProfileAuthCard = () => {
121120
items.push({
122121
text: m.controls_disable(),
123122
icon: 'minus-circle',
124-
onClick: () => mutateDisableEmailMfa(),
123+
onClick: () => mutateDisableEmailMfa(user.username),
125124
});
126125
}
127126
const res: MenuItemsGroup = {
@@ -133,6 +132,7 @@ export const ProfileAuthCard = () => {
133132
mutateDisableEmailMfa,
134133
mutateSetDefaultMfa,
135134
user.mfa_method,
135+
user.username,
136136
]);
137137

138138
const mfaMenuItems = useMemo(() => {
@@ -227,16 +227,20 @@ export const ProfileAuthCard = () => {
227227
items.push({
228228
icon: 'minus-circle',
229229
text: m.controls_disable(),
230-
onClick: () => {
231-
mutateDisableTotp();
232-
},
230+
onClick: () => mutateDisableTotp(user.username),
233231
});
234232
}
235233

236234
return {
237235
items,
238236
};
239-
}, [mutateDisableTotp, user.totp_enabled, mutateSetDefaultMfa, user.mfa_method]);
237+
}, [
238+
mutateDisableTotp,
239+
user.totp_enabled,
240+
mutateSetDefaultMfa,
241+
user.mfa_method,
242+
user.username,
243+
]);
240244

241245
return (
242246
<ProfileCard id="profile-auth-card">

web/src/shared/api/api.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ const api = {
203203
});
204204
},
205205
deleteUser: (username: string) => client.delete(`/user/${username}`),
206+
mfa: {
207+
totp: {
208+
disable: (username: string) => client.delete(`/user/${username}/totp`),
209+
},
210+
email: {
211+
disable: (username: string) => client.delete(`/user/${username}/email`),
212+
},
213+
},
206214
},
207215
webhook: {
208216
addWebhook: (data: AddWebhookRequest) => client.post('/webhook', data),
@@ -233,15 +241,13 @@ const api = {
233241
client.post<MfaCompleteResponse>('/auth/totp/verify', {
234242
code,
235243
}),
236-
disable: () => client.delete('/auth/totp'),
237244
},
238245
email: {
239246
init: () => client.post('/auth/email/init'),
240247
enable: (code: string) =>
241248
client.post<EnableMfaMethodResponse>('/auth/email', {
242249
code,
243250
}),
244-
disable: () => client.delete('/auth/email'),
245251
resend: () => client.get('/auth/email'),
246252
verify: (code: string) =>
247253
client.post<MfaCompleteResponse>('/auth/email/verify', { code }),

0 commit comments

Comments
 (0)