feat(core): Improve ldap/saml toggle and tests (#5771)
* improve ldap/saml toggle and tests * import cleanup * reject regular login users when saml is enabled * lint fix
This commit is contained in:
committed by
GitHub
parent
30aeeb70b4
commit
47ee357059
@@ -26,6 +26,11 @@ import type { ConnectionSecurity, LdapConfig } from './types';
|
||||
import { jsonParse, LoggerProxy as Logger } from 'n8n-workflow';
|
||||
import { License } from '@/License';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import {
|
||||
isEmailCurrentAuthenticationMethod,
|
||||
isLdapCurrentAuthenticationMethod,
|
||||
setCurrentAuthenticationMethod,
|
||||
} from '@/sso/ssoHelpers';
|
||||
|
||||
/**
|
||||
* Check whether the LDAP feature is disabled in the instance
|
||||
@@ -50,8 +55,24 @@ export const setLdapLoginLabel = (value: string): void => {
|
||||
/**
|
||||
* Set the LDAP login enabled to the configuration object
|
||||
*/
|
||||
export const setLdapLoginEnabled = (value: boolean): void => {
|
||||
config.set(LDAP_LOGIN_ENABLED, value);
|
||||
export const setLdapLoginEnabled = async (value: boolean): Promise<void> => {
|
||||
if (config.get(LDAP_LOGIN_ENABLED) === value) {
|
||||
return;
|
||||
}
|
||||
// only one auth method can be active at a time, with email being the default
|
||||
if (value && isEmailCurrentAuthenticationMethod()) {
|
||||
// enable ldap login and disable email login, but only if email is the current auth method
|
||||
config.set(LDAP_LOGIN_ENABLED, true);
|
||||
await setCurrentAuthenticationMethod('ldap');
|
||||
} else if (!value && isLdapCurrentAuthenticationMethod()) {
|
||||
// disable ldap login, but only if ldap is the current auth method
|
||||
config.set(LDAP_LOGIN_ENABLED, false);
|
||||
await setCurrentAuthenticationMethod('email');
|
||||
} else {
|
||||
Logger.warn(
|
||||
'Cannot switch LDAP login enabled state when an authentication method other than email is active',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -126,8 +147,8 @@ export const getLdapConfig = async (): Promise<LdapConfig> => {
|
||||
/**
|
||||
* Take the LDAP configuration and set login enabled and login label to the config object
|
||||
*/
|
||||
export const setGlobalLdapConfigVariables = (ldapConfig: LdapConfig): void => {
|
||||
setLdapLoginEnabled(ldapConfig.loginEnabled);
|
||||
export const setGlobalLdapConfigVariables = async (ldapConfig: LdapConfig): Promise<void> => {
|
||||
await setLdapLoginEnabled(ldapConfig.loginEnabled);
|
||||
setLdapLoginLabel(ldapConfig.loginLabel);
|
||||
};
|
||||
|
||||
@@ -175,7 +196,7 @@ export const updateLdapConfig = async (ldapConfig: LdapConfig): Promise<void> =>
|
||||
{ key: LDAP_FEATURE_NAME },
|
||||
{ value: JSON.stringify(ldapConfig), loadOnStartup: true },
|
||||
);
|
||||
setGlobalLdapConfigVariables(ldapConfig);
|
||||
await setGlobalLdapConfigVariables(ldapConfig);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,7 +218,7 @@ export const handleLdapInit = async (): Promise<void> => {
|
||||
|
||||
const ldapConfig = await getLdapConfig();
|
||||
|
||||
setGlobalLdapConfigVariables(ldapConfig);
|
||||
await setGlobalLdapConfigVariables(ldapConfig);
|
||||
|
||||
// init LDAP manager with the current
|
||||
// configuration
|
||||
|
||||
@@ -19,8 +19,10 @@ import type {
|
||||
} from '@/Interfaces';
|
||||
import { handleEmailLogin, handleLdapLogin } from '@/auth';
|
||||
import type { PostHogClient } from '@/posthog';
|
||||
import { isSamlCurrentAuthenticationMethod } from '../sso/ssoHelpers';
|
||||
import { SamlUrls } from '../sso/saml/constants';
|
||||
import {
|
||||
isLdapCurrentAuthenticationMethod,
|
||||
isSamlCurrentAuthenticationMethod,
|
||||
} from '@/sso/ssoHelpers';
|
||||
|
||||
@RestController()
|
||||
export class AuthController {
|
||||
@@ -73,19 +75,12 @@ export class AuthController {
|
||||
if (preliminaryUser?.globalRole?.name === 'owner') {
|
||||
user = preliminaryUser;
|
||||
} else {
|
||||
// TODO:SAML - uncomment this block when we have a way to redirect users to the SSO flow
|
||||
// if (doRedirectUsersFromLoginToSsoFlow()) {
|
||||
res.redirect(SamlUrls.restInitSSO);
|
||||
return;
|
||||
// return withFeatureFlags(this.postHog, sanitizeUser(preliminaryUser));
|
||||
// } else {
|
||||
// throw new AuthError(
|
||||
// 'Login with username and password is disabled due to SAML being the default authentication method. Please use SAML to log in.',
|
||||
// );
|
||||
// }
|
||||
throw new AuthError('SAML is enabled, please log in with SAML');
|
||||
}
|
||||
} else if (isLdapCurrentAuthenticationMethod()) {
|
||||
user = await handleLdapLogin(email, password);
|
||||
} else {
|
||||
user = (await handleLdapLogin(email, password)) ?? (await handleEmailLogin(email, password));
|
||||
user = await handleEmailLogin(email, password);
|
||||
}
|
||||
if (user) {
|
||||
await issueCookie(res, user);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
isSamlCurrentAuthenticationMethod,
|
||||
setCurrentAuthenticationMethod,
|
||||
} from '../ssoHelpers';
|
||||
import { LoggerProxy } from 'n8n-workflow';
|
||||
/**
|
||||
* Check whether the SAML feature is licensed and enabled in the instance
|
||||
*/
|
||||
@@ -29,14 +30,19 @@ export function getSamlLoginLabel(): string {
|
||||
|
||||
// can only toggle between email and saml, not directly to e.g. ldap
|
||||
export async function setSamlLoginEnabled(enabled: boolean): Promise<void> {
|
||||
if (enabled) {
|
||||
if (isEmailCurrentAuthenticationMethod()) {
|
||||
config.set(SAML_LOGIN_ENABLED, true);
|
||||
await setCurrentAuthenticationMethod('saml');
|
||||
}
|
||||
} else {
|
||||
if (config.get(SAML_LOGIN_ENABLED) === enabled) {
|
||||
return;
|
||||
}
|
||||
if (enabled && isEmailCurrentAuthenticationMethod()) {
|
||||
config.set(SAML_LOGIN_ENABLED, true);
|
||||
await setCurrentAuthenticationMethod('saml');
|
||||
} else if (!enabled && isSamlCurrentAuthenticationMethod()) {
|
||||
config.set(SAML_LOGIN_ENABLED, false);
|
||||
await setCurrentAuthenticationMethod('email');
|
||||
} else {
|
||||
LoggerProxy.warn(
|
||||
'Cannot switch SAML login enabled state when an authentication method other than email is active',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,22 +2,12 @@ import config from '@/config';
|
||||
import * as Db from '@/Db';
|
||||
import type { AuthProviderType } from '@/databases/entities/AuthIdentity';
|
||||
|
||||
export function isSamlCurrentAuthenticationMethod(): boolean {
|
||||
return config.getEnv('userManagement.authenticationMethod') === 'saml';
|
||||
}
|
||||
|
||||
export function isEmailCurrentAuthenticationMethod(): boolean {
|
||||
return config.getEnv('userManagement.authenticationMethod') === 'email';
|
||||
}
|
||||
|
||||
export function isSsoJustInTimeProvisioningEnabled(): boolean {
|
||||
return config.getEnv('sso.justInTimeProvisioning');
|
||||
}
|
||||
|
||||
export function doRedirectUsersFromLoginToSsoFlow(): boolean {
|
||||
return config.getEnv('sso.redirectLoginToSso');
|
||||
}
|
||||
|
||||
/**
|
||||
* Only one authentication method can be active at a time. This function sets the current authentication method
|
||||
* and saves it to the database.
|
||||
* SSO methods should only switch to email and then to another method. Email can switch to any method.
|
||||
* @param authenticationMethod
|
||||
*/
|
||||
export async function setCurrentAuthenticationMethod(
|
||||
authenticationMethod: AuthProviderType,
|
||||
): Promise<void> {
|
||||
@@ -28,3 +18,27 @@ export async function setCurrentAuthenticationMethod(
|
||||
loadOnStartup: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function getCurrentAuthenticationMethod(): AuthProviderType {
|
||||
return config.getEnv('userManagement.authenticationMethod');
|
||||
}
|
||||
|
||||
export function isSamlCurrentAuthenticationMethod(): boolean {
|
||||
return getCurrentAuthenticationMethod() === 'saml';
|
||||
}
|
||||
|
||||
export function isLdapCurrentAuthenticationMethod(): boolean {
|
||||
return getCurrentAuthenticationMethod() === 'ldap';
|
||||
}
|
||||
|
||||
export function isEmailCurrentAuthenticationMethod(): boolean {
|
||||
return getCurrentAuthenticationMethod() === 'email';
|
||||
}
|
||||
|
||||
export function isSsoJustInTimeProvisioningEnabled(): boolean {
|
||||
return config.getEnv('sso.justInTimeProvisioning');
|
||||
}
|
||||
|
||||
export function doRedirectUsersFromLoginToSsoFlow(): boolean {
|
||||
return config.getEnv('sso.redirectLoginToSso');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user