mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-24 23:22:38 +08:00
fix(editor): Allow LDAP users to configure n8n 2FA in personal settings (#34655)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cd1e48e5f5
commit
2b1e4b8910
@@ -162,6 +162,29 @@ describe('SettingsPersonalView', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when signed in via LDAP', () => {
|
||||
beforeEach(() => {
|
||||
vi.spyOn(ssoStore, 'isEnterpriseLdapEnabled', 'get').mockReturnValue(true);
|
||||
vi.spyOn(settingsStore, 'isMfaFeatureEnabled', 'get').mockReturnValue(true);
|
||||
usersStore.usersById[currentUser.id] = { ...currentUser, signInType: 'ldap' };
|
||||
});
|
||||
|
||||
it('should let a member configure MFA while hiding password change', async () => {
|
||||
vi.spyOn(usersStore, 'isInstanceOwner', 'get').mockReturnValue(false);
|
||||
|
||||
const { queryByTestId, getAllByRole } = renderComponent({ pinia });
|
||||
await waitAllPromises();
|
||||
|
||||
// LDAP has no native 2FA, so n8n's own MFA stays configurable...
|
||||
expect(queryByTestId('mfa-section')).toBeInTheDocument();
|
||||
// ...but password/email remain managed externally.
|
||||
expect(queryByTestId('change-password-link')).not.toBeInTheDocument();
|
||||
expect(
|
||||
getAllByRole('textbox').find((el) => el.getAttribute('type') === 'email'),
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
test.each([
|
||||
['Default', ROLE.Default, false, 'Default role for new users'],
|
||||
['Member', ROLE.Member, false, 'Create and manage own workflows and credentials'],
|
||||
|
||||
@@ -97,15 +97,17 @@ const isManagedByEnv = computed((): boolean => {
|
||||
return currentUser.value?.isManagedByEnv ?? false;
|
||||
});
|
||||
|
||||
const isLdapCurrentAuthMethod = computed((): boolean => {
|
||||
return ssoStore.isEnterpriseLdapEnabled && currentUser.value?.signInType === 'ldap';
|
||||
});
|
||||
|
||||
const isExternalAuthEnabled = computed((): boolean => {
|
||||
const isLdapEnabled =
|
||||
ssoStore.isEnterpriseLdapEnabled && currentUser.value?.signInType === 'ldap';
|
||||
const isSamlEnabled = ssoStore.isSamlLoginEnabled && ssoStore.isDefaultAuthenticationSaml;
|
||||
const isOidcEnabled =
|
||||
ssoStore.isEnterpriseOidcEnabled &&
|
||||
ssoStore.isOidcLoginEnabled &&
|
||||
currentUser.value?.signInType === 'oidc';
|
||||
return isLdapEnabled || isSamlEnabled || isOidcEnabled;
|
||||
return isLdapCurrentAuthMethod.value || isSamlEnabled || isOidcEnabled;
|
||||
});
|
||||
|
||||
const isPersonalSecurityEnabled = computed((): boolean => {
|
||||
@@ -122,6 +124,18 @@ const isMfaFeatureEnabled = computed((): boolean => {
|
||||
return settingsStore.isMfaFeatureEnabled;
|
||||
});
|
||||
|
||||
// Unlike SAML/OIDC, LDAP has no native 2FA, so n8n's own 2FA must stay
|
||||
// configurable for LDAP users even though password management is external.
|
||||
const canConfigureMfa = computed((): boolean => {
|
||||
return (
|
||||
isMfaFeatureEnabled.value && (isPersonalSecurityEnabled.value || isLdapCurrentAuthMethod.value)
|
||||
);
|
||||
});
|
||||
|
||||
const isSecuritySectionVisible = computed((): boolean => {
|
||||
return !isManagedByEnv.value && (isPersonalSecurityEnabled.value || canConfigureMfa.value);
|
||||
});
|
||||
|
||||
const hasAnyPersonalisationChanges = computed((): boolean => {
|
||||
return currentSelectedTheme.value !== uiStore.theme;
|
||||
});
|
||||
@@ -403,18 +417,18 @@ onBeforeUnmount(() => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isPersonalSecurityEnabled && !isManagedByEnv">
|
||||
<div v-if="isSecuritySectionVisible">
|
||||
<div class="mb-s">
|
||||
<N8nHeading size="large">{{ i18n.baseText('settings.personal.security') }}</N8nHeading>
|
||||
</div>
|
||||
<div class="mb-s">
|
||||
<div v-if="isPersonalSecurityEnabled" class="mb-s">
|
||||
<N8nInputLabel :label="i18n.baseText('auth.password')">
|
||||
<N8nLink data-test-id="change-password-link" @click="openPasswordModal">{{
|
||||
i18n.baseText('auth.changePassword')
|
||||
}}</N8nLink>
|
||||
</N8nInputLabel>
|
||||
</div>
|
||||
<div v-if="isMfaFeatureEnabled" data-test-id="mfa-section">
|
||||
<div v-if="canConfigureMfa" data-test-id="mfa-section">
|
||||
<div class="mb-xs">
|
||||
<N8nInputLabel :label="i18n.baseText('settings.personal.mfa.section.title')" />
|
||||
<N8nText :bold="false" :class="$style.infoText">
|
||||
|
||||
Reference in New Issue
Block a user