FIX: Regression when enforced 2FA is enabled (#24415)

This commit is contained in:
Penar Musaraj 2023-11-16 11:52:12 -05:00 committed by GitHub
parent f19fd75af9
commit bcfb1a423d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 26 deletions

View File

@ -45,7 +45,7 @@ export default class ConfirmSession extends Component {
return; return;
} }
const result = await ajax("/u/confirm-session", { const result = await ajax("/u/confirm-session.json", {
type: "POST", type: "POST",
data: { publicKeyCredential }, data: { publicKeyCredential },
}); });
@ -67,7 +67,7 @@ export default class ConfirmSession extends Component {
? null ? null
: I18n.t("user.confirm_access.incorrect_password"); : I18n.t("user.confirm_access.incorrect_password");
const result = await ajax("/u/confirm-session", { const result = await ajax("/u/confirm-session.json", {
type: "POST", type: "POST",
data: { data: {
password: this.password, password: this.password,

View File

@ -2,6 +2,7 @@ import Controller from "@ember/controller";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import ConfirmSession from "discourse/components/dialog-messages/confirm-session";
import SecondFactorConfirmPhrase from "discourse/components/dialog-messages/second-factor-confirm-phrase"; import SecondFactorConfirmPhrase from "discourse/components/dialog-messages/second-factor-confirm-phrase";
import SecondFactorAddSecurityKey from "discourse/components/modal/second-factor-add-security-key"; import SecondFactorAddSecurityKey from "discourse/components/modal/second-factor-add-security-key";
import SecondFactorAddTotp from "discourse/components/modal/second-factor-add-totp"; import SecondFactorAddTotp from "discourse/components/modal/second-factor-add-totp";
@ -25,11 +26,11 @@ export default Controller.extend(CanCheckEmails, {
newUsername: null, newUsername: null,
backupEnabled: alias("model.second_factor_backup_enabled"), backupEnabled: alias("model.second_factor_backup_enabled"),
secondFactorMethod: SECOND_FACTOR_METHODS.TOTP, secondFactorMethod: SECOND_FACTOR_METHODS.TOTP,
totps: null, totps: [],
security_keys: [],
init() { init() {
this._super(...arguments); this._super(...arguments);
this.set("totps", []);
}, },
@discourseComputed @discourseComputed
@ -47,6 +48,36 @@ export default Controller.extend(CanCheckEmails, {
return totps.length > 0 || security_keys.length > 0; return totps.length > 0 || security_keys.length > 0;
}, },
async createToTpModal() {
try {
await this.modal.show(SecondFactorAddTotp, {
model: {
secondFactor: this.model,
markDirty: () => this.markDirty(),
onError: (e) => this.handleError(e),
},
});
this.loadSecondFactors();
} catch (error) {
popupAjaxError(error);
}
},
async createSecurityKeyModal() {
try {
await this.modal.show(SecondFactorAddSecurityKey, {
model: {
secondFactor: this.model,
markDirty: this.markDirty,
onError: this.handleError,
},
});
this.loadSecondFactors();
} catch (error) {
popupAjaxError(error);
}
},
@action @action
handleError(error) { handleError(error) {
if (error.jqXHR) { if (error.jqXHR) {
@ -104,6 +135,46 @@ export default Controller.extend(CanCheckEmails, {
this.set("dirty", true); this.set("dirty", true);
}, },
@action
async createTotp() {
try {
const trustedSession = await this.model.trustedSession();
if (!trustedSession.success) {
this.dialog.dialog({
title: I18n.t("user.confirm_access.title"),
type: "notice",
bodyComponent: ConfirmSession,
didConfirm: () => this.createToTpModal(),
});
} else {
await this.createToTpModal();
}
} catch (error) {
popupAjaxError(error);
}
},
@action
async createSecurityKey() {
try {
const trustedSession = await this.model.trustedSession();
if (!trustedSession.success) {
this.dialog.dialog({
title: I18n.t("user.confirm_access.title"),
type: "notice",
bodyComponent: ConfirmSession,
didConfirm: () => this.createSecurityKeyModal(),
});
} else {
await this.createSecurityKeyModal();
}
} catch (error) {
popupAjaxError(error);
}
},
actions: { actions: {
disableAllSecondFactors() { disableAllSecondFactors() {
if (this.loading) { if (this.loading) {
@ -237,28 +308,6 @@ export default Controller.extend(CanCheckEmails, {
}); });
}, },
async createTotp() {
await this.modal.show(SecondFactorAddTotp, {
model: {
secondFactor: this.model,
markDirty: () => this.markDirty(),
onError: (e) => this.handleError(e),
},
});
this.loadSecondFactors();
},
async createSecurityKey() {
await this.modal.show(SecondFactorAddSecurityKey, {
model: {
secondFactor: this.model,
markDirty: this.markDirty,
onError: this.handleError,
},
});
this.loadSecondFactors();
},
async editSecurityKey(security_key) { async editSecurityKey(security_key) {
await this.modal.show(SecondFactorEditSecurityKey, { await this.modal.show(SecondFactorEditSecurityKey, {
model: { model: {

View File

@ -51,6 +51,10 @@ acceptance("User Preferences - Second Factor", function (needs) {
backup_codes: ["dsffdsd", "fdfdfdsf", "fddsds"], backup_codes: ["dsffdsd", "fdfdfdsf", "fddsds"],
}); });
}); });
server.get("/u/trusted-session.json", () => {
return helper.response({ success: "OK" });
});
}); });
test("second factor totp", async function (assert) { test("second factor totp", async function (assert) {

View File

@ -109,13 +109,38 @@ describe "User preferences for Security", type: :system do
end end
end end
shared_examples "enforced second factor" do
it "allows user to add 2FA" do
SiteSetting.enforce_second_factor = "all"
visit("/")
expect(page).to have_selector(
".alert-error",
text: "You are required to enable two-factor authentication before accessing this site.",
)
expect(page).to have_css(".user-preferences .totp")
expect(page).to have_css(".user-preferences .security-key")
find(".user-preferences .totp .btn.new-totp").click
find(".dialog-body input#password").fill_in(with: password)
find(".confirm-session .btn-primary").click
expect(page).to have_css(".qr-code")
end
end
context "when desktop" do context "when desktop" do
include_examples "security keys" include_examples "security keys"
include_examples "passkeys" include_examples "passkeys"
include_examples "enforced second factor"
end end
context "when mobile", mobile: true do context "when mobile", mobile: true do
include_examples "security keys" include_examples "security keys"
include_examples "passkeys" include_examples "passkeys"
include_examples "enforced second factor"
end end
end end