mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
feat(core): Add SAML settings and consolidate LDAP under SSO (#5574)
* consolidate SSO settings * update saml settings * fix type error
This commit is contained in:
parent
f61d779667
commit
31cc8de829
|
@ -488,9 +488,15 @@ export interface IN8nUISettings {
|
||||||
personalizationSurveyEnabled: boolean;
|
personalizationSurveyEnabled: boolean;
|
||||||
defaultLocale: string;
|
defaultLocale: string;
|
||||||
userManagement: IUserManagementSettings;
|
userManagement: IUserManagementSettings;
|
||||||
ldap: {
|
sso: {
|
||||||
loginLabel: string;
|
saml: {
|
||||||
loginEnabled: boolean;
|
loginLabel: string;
|
||||||
|
loginEnabled: boolean;
|
||||||
|
};
|
||||||
|
ldap: {
|
||||||
|
loginLabel: string;
|
||||||
|
loginEnabled: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
publicApi: IPublicApiSettings;
|
publicApi: IPublicApiSettings;
|
||||||
workflowTagsDisabled: boolean;
|
workflowTagsDisabled: boolean;
|
||||||
|
|
|
@ -4,9 +4,9 @@ export const LDAP_FEATURE_NAME = 'features.ldap';
|
||||||
|
|
||||||
export const LDAP_ENABLED = 'enterprise.features.ldap';
|
export const LDAP_ENABLED = 'enterprise.features.ldap';
|
||||||
|
|
||||||
export const LDAP_LOGIN_LABEL = 'ldap.loginLabel';
|
export const LDAP_LOGIN_LABEL = 'sso.ldap.loginLabel';
|
||||||
|
|
||||||
export const LDAP_LOGIN_ENABLED = 'ldap.loginEnabled';
|
export const LDAP_LOGIN_ENABLED = 'sso.ldap.loginEnabled';
|
||||||
|
|
||||||
export const BINARY_AD_ATTRIBUTES = ['objectGUID', 'objectSid'];
|
export const BINARY_AD_ATTRIBUTES = ['objectGUID', 'objectSid'];
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ import { eventBus } from './eventbus';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import { InternalHooks } from './InternalHooks';
|
import { InternalHooks } from './InternalHooks';
|
||||||
import { getStatusUsingPreviousExecutionStatusMethod } from './executions/executionHelpers';
|
import { getStatusUsingPreviousExecutionStatusMethod } from './executions/executionHelpers';
|
||||||
import { isSamlLicensed } from './sso/saml/samlHelpers';
|
import { getSamlLoginLabel, isSamlLoginEnabled, isSamlLicensed } from './sso/saml/samlHelpers';
|
||||||
import { samlControllerPublic } from './sso/saml/routes/saml.controller.public.ee';
|
import { samlControllerPublic } from './sso/saml/routes/saml.controller.public.ee';
|
||||||
import { SamlService } from './sso/saml/saml.service.ee';
|
import { SamlService } from './sso/saml/saml.service.ee';
|
||||||
import { samlControllerProtected } from './sso/saml/routes/saml.controller.protected.ee';
|
import { samlControllerProtected } from './sso/saml/routes/saml.controller.protected.ee';
|
||||||
|
@ -258,9 +258,15 @@ class Server extends AbstractServer {
|
||||||
config.getEnv('userManagement.skipInstanceOwnerSetup') === false,
|
config.getEnv('userManagement.skipInstanceOwnerSetup') === false,
|
||||||
smtpSetup: isEmailSetUp(),
|
smtpSetup: isEmailSetUp(),
|
||||||
},
|
},
|
||||||
ldap: {
|
sso: {
|
||||||
loginEnabled: false,
|
saml: {
|
||||||
loginLabel: '',
|
loginEnabled: false,
|
||||||
|
loginLabel: '',
|
||||||
|
},
|
||||||
|
ldap: {
|
||||||
|
loginEnabled: false,
|
||||||
|
loginLabel: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
publicApi: {
|
publicApi: {
|
||||||
enabled: !config.getEnv('publicApi.disabled'),
|
enabled: !config.getEnv('publicApi.disabled'),
|
||||||
|
@ -325,12 +331,19 @@ class Server extends AbstractServer {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLdapEnabled()) {
|
if (isLdapEnabled()) {
|
||||||
Object.assign(this.frontendSettings.ldap, {
|
Object.assign(this.frontendSettings.sso.ldap, {
|
||||||
loginLabel: getLdapLoginLabel(),
|
loginLabel: getLdapLoginLabel(),
|
||||||
loginEnabled: isLdapLoginEnabled(),
|
loginEnabled: isLdapLoginEnabled(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSamlLicensed()) {
|
||||||
|
Object.assign(this.frontendSettings.sso.saml, {
|
||||||
|
loginLabel: getSamlLoginLabel(),
|
||||||
|
loginEnabled: isSamlLoginEnabled(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (config.get('nodes.packagesMissing').length > 0) {
|
if (config.get('nodes.packagesMissing').length > 0) {
|
||||||
this.frontendSettings.missingPackages = true;
|
this.frontendSettings.missingPackages = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1023,23 +1023,25 @@ export const schema = {
|
||||||
doc: 'Whether to automatically redirect users from login dialog to initialize SSO flow.',
|
doc: 'Whether to automatically redirect users from login dialog to initialize SSO flow.',
|
||||||
},
|
},
|
||||||
saml: {
|
saml: {
|
||||||
enabled: {
|
loginEnabled: {
|
||||||
format: Boolean,
|
format: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
doc: 'Whether to enable SAML SSO.',
|
doc: 'Whether to enable SAML SSO.',
|
||||||
},
|
},
|
||||||
|
loginLabel: {
|
||||||
|
format: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
ldap: {
|
||||||
|
loginEnabled: {
|
||||||
// TODO: move into sso settings
|
format: Boolean,
|
||||||
ldap: {
|
default: false,
|
||||||
loginEnabled: {
|
},
|
||||||
format: Boolean,
|
loginLabel: {
|
||||||
default: false,
|
format: String,
|
||||||
},
|
default: '',
|
||||||
loginLabel: {
|
},
|
||||||
format: String,
|
|
||||||
default: '',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -23,3 +23,9 @@ export class SamlUrls {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SAML_PREFERENCES_DB_KEY = 'features.saml';
|
export const SAML_PREFERENCES_DB_KEY = 'features.saml';
|
||||||
|
|
||||||
|
export const SAML_ENTERPRISE_FEATURE_ENABLED = 'enterprise.features.saml';
|
||||||
|
|
||||||
|
export const SAML_LOGIN_LABEL = 'sso.saml.loginLabel';
|
||||||
|
|
||||||
|
export const SAML_LOGIN_ENABLED = 'sso.saml.loginEnabled';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { RequestHandler } from 'express';
|
import type { RequestHandler } from 'express';
|
||||||
import type { AuthenticatedRequest } from '../../../requests';
|
import type { AuthenticatedRequest } from '../../../requests';
|
||||||
import { isSamlCurrentAuthenticationMethod } from '../../ssoHelpers';
|
import { isSamlCurrentAuthenticationMethod } from '../../ssoHelpers';
|
||||||
import { isSamlEnabled, isSamlLicensed } from '../samlHelpers';
|
import { isSamlLoginEnabled, isSamlLicensed } from '../samlHelpers';
|
||||||
|
|
||||||
export const samlLicensedOwnerMiddleware: RequestHandler = (
|
export const samlLicensedOwnerMiddleware: RequestHandler = (
|
||||||
req: AuthenticatedRequest,
|
req: AuthenticatedRequest,
|
||||||
|
@ -16,7 +16,7 @@ export const samlLicensedOwnerMiddleware: RequestHandler = (
|
||||||
};
|
};
|
||||||
|
|
||||||
export const samlLicensedAndEnabledMiddleware: RequestHandler = (req, res, next) => {
|
export const samlLicensedAndEnabledMiddleware: RequestHandler = (req, res, next) => {
|
||||||
if (isSamlEnabled() && isSamlLicensed() && isSamlCurrentAuthenticationMethod()) {
|
if (isSamlLoginEnabled() && isSamlLicensed() && isSamlCurrentAuthenticationMethod()) {
|
||||||
next();
|
next();
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ status: 'error', message: 'Unauthorized' });
|
res.status(401).json({ status: 'error', message: 'Unauthorized' });
|
||||||
|
|
|
@ -6,8 +6,9 @@ import {
|
||||||
import { SamlService } from '../saml.service.ee';
|
import { SamlService } from '../saml.service.ee';
|
||||||
import { SamlUrls } from '../constants';
|
import { SamlUrls } from '../constants';
|
||||||
import type { SamlConfiguration } from '../types/requests';
|
import type { SamlConfiguration } from '../types/requests';
|
||||||
import { AuthError } from '../../../ResponseHelper';
|
import { AuthError, BadRequestError } from '@/ResponseHelper';
|
||||||
import { issueCookie } from '../../../auth/jwt';
|
import { issueCookie } from '../../../auth/jwt';
|
||||||
|
import { isSamlPreferences } from '../samlHelpers';
|
||||||
|
|
||||||
export const samlControllerProtected = express.Router();
|
export const samlControllerProtected = express.Router();
|
||||||
|
|
||||||
|
@ -18,8 +19,8 @@ export const samlControllerProtected = express.Router();
|
||||||
samlControllerProtected.get(
|
samlControllerProtected.get(
|
||||||
SamlUrls.config,
|
SamlUrls.config,
|
||||||
samlLicensedOwnerMiddleware,
|
samlLicensedOwnerMiddleware,
|
||||||
async (req: SamlConfiguration.Read, res: express.Response) => {
|
(req: SamlConfiguration.Read, res: express.Response) => {
|
||||||
const prefs = await SamlService.getInstance().getSamlPreferences();
|
const prefs = SamlService.getInstance().getSamlPreferences();
|
||||||
return res.send(prefs);
|
return res.send(prefs);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -32,11 +33,12 @@ samlControllerProtected.post(
|
||||||
SamlUrls.config,
|
SamlUrls.config,
|
||||||
samlLicensedOwnerMiddleware,
|
samlLicensedOwnerMiddleware,
|
||||||
async (req: SamlConfiguration.Update, res: express.Response) => {
|
async (req: SamlConfiguration.Update, res: express.Response) => {
|
||||||
const result = await SamlService.getInstance().setSamlPreferences({
|
if (isSamlPreferences(req.body)) {
|
||||||
metadata: req.body.metadata,
|
const result = await SamlService.getInstance().setSamlPreferences(req.body);
|
||||||
mapping: req.body.mapping,
|
return res.send(result);
|
||||||
});
|
} else {
|
||||||
return res.send(result);
|
throw new BadRequestError('Body is not a SamlPreferences object');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ import { IdentityProvider } from 'samlify';
|
||||||
import {
|
import {
|
||||||
createUserFromSamlAttributes,
|
createUserFromSamlAttributes,
|
||||||
getMappedSamlAttributesFromFlowResult,
|
getMappedSamlAttributesFromFlowResult,
|
||||||
|
getSamlLoginLabel,
|
||||||
|
isSamlLoginEnabled,
|
||||||
|
setSamlLoginEnabled,
|
||||||
|
setSamlLoginLabel,
|
||||||
updateUserFromSamlAttributes,
|
updateUserFromSamlAttributes,
|
||||||
} from './samlHelpers';
|
} from './samlHelpers';
|
||||||
|
|
||||||
|
@ -142,16 +146,20 @@ export class SamlService {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSamlPreferences(): Promise<SamlPreferences> {
|
getSamlPreferences(): SamlPreferences {
|
||||||
return {
|
return {
|
||||||
mapping: this.attributeMapping,
|
mapping: this.attributeMapping,
|
||||||
metadata: this.metadata,
|
metadata: this.metadata,
|
||||||
|
loginEnabled: isSamlLoginEnabled(),
|
||||||
|
loginLabel: getSamlLoginLabel(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async setSamlPreferences(prefs: SamlPreferences): Promise<void> {
|
async setSamlPreferences(prefs: SamlPreferences): Promise<void> {
|
||||||
this.attributeMapping = prefs.mapping;
|
this.attributeMapping = prefs.mapping;
|
||||||
this.metadata = prefs.metadata;
|
this.metadata = prefs.metadata;
|
||||||
|
setSamlLoginEnabled(prefs.loginEnabled);
|
||||||
|
setSamlLoginLabel(prefs.loginLabel);
|
||||||
this.getIdentityProviderInstance(true);
|
this.getIdentityProviderInstance(true);
|
||||||
await this.saveSamlPreferences();
|
await this.saveSamlPreferences();
|
||||||
}
|
}
|
||||||
|
@ -163,10 +171,9 @@ export class SamlService {
|
||||||
if (samlPreferences) {
|
if (samlPreferences) {
|
||||||
const prefs = jsonParse<SamlPreferences>(samlPreferences.value);
|
const prefs = jsonParse<SamlPreferences>(samlPreferences.value);
|
||||||
if (prefs) {
|
if (prefs) {
|
||||||
this.attributeMapping = prefs.mapping;
|
await this.setSamlPreferences(prefs);
|
||||||
this.metadata = prefs.metadata;
|
return prefs;
|
||||||
}
|
}
|
||||||
return prefs;
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,20 +182,14 @@ export class SamlService {
|
||||||
const samlPreferences = await Db.collections.Settings.findOne({
|
const samlPreferences = await Db.collections.Settings.findOne({
|
||||||
where: { key: SAML_PREFERENCES_DB_KEY },
|
where: { key: SAML_PREFERENCES_DB_KEY },
|
||||||
});
|
});
|
||||||
|
const settingsValue = JSON.stringify(this.getSamlPreferences());
|
||||||
if (samlPreferences) {
|
if (samlPreferences) {
|
||||||
samlPreferences.value = JSON.stringify({
|
samlPreferences.value = settingsValue;
|
||||||
mapping: this.attributeMapping,
|
|
||||||
metadata: this.metadata,
|
|
||||||
});
|
|
||||||
samlPreferences.loadOnStartup = true;
|
|
||||||
await Db.collections.Settings.save(samlPreferences);
|
await Db.collections.Settings.save(samlPreferences);
|
||||||
} else {
|
} else {
|
||||||
await Db.collections.Settings.save({
|
await Db.collections.Settings.save({
|
||||||
key: SAML_PREFERENCES_DB_KEY,
|
key: SAML_PREFERENCES_DB_KEY,
|
||||||
value: JSON.stringify({
|
value: settingsValue,
|
||||||
mapping: this.attributeMapping,
|
|
||||||
metadata: this.metadata,
|
|
||||||
}),
|
|
||||||
loadOnStartup: true,
|
loadOnStartup: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,24 +9,43 @@ import type { SamlPreferences } from './types/samlPreferences';
|
||||||
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
import type { SamlUserAttributes } from './types/samlUserAttributes';
|
||||||
import type { FlowResult } from 'samlify/types/src/flow';
|
import type { FlowResult } from 'samlify/types/src/flow';
|
||||||
import type { SamlAttributeMapping } from './types/samlAttributeMapping';
|
import type { SamlAttributeMapping } from './types/samlAttributeMapping';
|
||||||
|
import { SAML_ENTERPRISE_FEATURE_ENABLED, SAML_LOGIN_ENABLED, SAML_LOGIN_LABEL } from './constants';
|
||||||
/**
|
/**
|
||||||
* Check whether the SAML feature is licensed and enabled in the instance
|
* Check whether the SAML feature is licensed and enabled in the instance
|
||||||
*/
|
*/
|
||||||
export function isSamlEnabled(): boolean {
|
export function isSamlLoginEnabled(): boolean {
|
||||||
return config.getEnv('sso.saml.enabled');
|
return config.getEnv(SAML_LOGIN_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSamlLoginLabel(): string {
|
||||||
|
return config.getEnv(SAML_LOGIN_LABEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSamlLoginEnabled(enabled: boolean): void {
|
||||||
|
config.set(SAML_LOGIN_ENABLED, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSamlLoginLabel(label: string): void {
|
||||||
|
config.set(SAML_LOGIN_LABEL, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSamlLicensed(): boolean {
|
export function isSamlLicensed(): boolean {
|
||||||
const license = getLicense();
|
const license = getLicense();
|
||||||
return (
|
return (
|
||||||
isUserManagementEnabled() &&
|
isUserManagementEnabled() &&
|
||||||
(license.isSamlEnabled() || config.getEnv('enterprise.features.saml'))
|
(license.isSamlEnabled() || config.getEnv(SAML_ENTERPRISE_FEATURE_ENABLED))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isSamlPreferences = (candidate: unknown): candidate is SamlPreferences => {
|
export const isSamlPreferences = (candidate: unknown): candidate is SamlPreferences => {
|
||||||
const o = candidate as SamlPreferences;
|
const o = candidate as SamlPreferences;
|
||||||
return typeof o === 'object' && typeof o.metadata === 'string' && typeof o.mapping === 'object';
|
return (
|
||||||
|
typeof o === 'object' &&
|
||||||
|
typeof o.metadata === 'string' &&
|
||||||
|
typeof o.mapping === 'object' &&
|
||||||
|
o.mapping !== null &&
|
||||||
|
o.loginEnabled !== undefined
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function generatePassword(): string {
|
export function generatePassword(): string {
|
||||||
|
|
|
@ -3,5 +3,6 @@ import type { SamlAttributeMapping } from './samlAttributeMapping';
|
||||||
export interface SamlPreferences {
|
export interface SamlPreferences {
|
||||||
mapping: SamlAttributeMapping;
|
mapping: SamlAttributeMapping;
|
||||||
metadata: string;
|
metadata: string;
|
||||||
//TODO:SAML: add fields for separate SAML settins to generate metadata from
|
loginEnabled: boolean;
|
||||||
|
loginLabel: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -766,9 +766,15 @@ export interface IN8nUISettings {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
ldap: {
|
sso: {
|
||||||
loginLabel: string;
|
saml: {
|
||||||
loginEnabled: boolean;
|
loginLabel: string;
|
||||||
|
loginEnabled: boolean;
|
||||||
|
};
|
||||||
|
ldap: {
|
||||||
|
loginLabel: string;
|
||||||
|
loginEnabled: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
onboardingCallPromptEnabled: boolean;
|
onboardingCallPromptEnabled: boolean;
|
||||||
allowedModules: {
|
allowedModules: {
|
||||||
|
@ -1197,6 +1203,10 @@ export interface ISettingsState {
|
||||||
loginLabel: string;
|
loginLabel: string;
|
||||||
loginEnabled: boolean;
|
loginEnabled: boolean;
|
||||||
};
|
};
|
||||||
|
saml: {
|
||||||
|
loginLabel: string;
|
||||||
|
loginEnabled: boolean;
|
||||||
|
};
|
||||||
onboardingCallPromptEnabled: boolean;
|
onboardingCallPromptEnabled: boolean;
|
||||||
saveDataErrorExecution: string;
|
saveDataErrorExecution: string;
|
||||||
saveDataSuccessExecution: string;
|
saveDataSuccessExecution: string;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
WorkflowCallerPolicyDefaultOption,
|
WorkflowCallerPolicyDefaultOption,
|
||||||
ILdapConfig,
|
ILdapConfig,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
import { ITelemetrySettings } from 'n8n-workflow';
|
import { IDataObject, ITelemetrySettings } from 'n8n-workflow';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import { useRootStore } from './n8nRootStore';
|
import { useRootStore } from './n8nRootStore';
|
||||||
|
@ -54,6 +54,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||||
loginLabel: '',
|
loginLabel: '',
|
||||||
loginEnabled: false,
|
loginEnabled: false,
|
||||||
},
|
},
|
||||||
|
saml: {
|
||||||
|
loginLabel: '',
|
||||||
|
loginEnabled: false,
|
||||||
|
},
|
||||||
onboardingCallPromptEnabled: false,
|
onboardingCallPromptEnabled: false,
|
||||||
saveDataErrorExecution: 'all',
|
saveDataErrorExecution: 'all',
|
||||||
saveDataSuccessExecution: 'all',
|
saveDataSuccessExecution: 'all',
|
||||||
|
@ -87,6 +91,12 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||||
ldapLoginLabel(): string {
|
ldapLoginLabel(): string {
|
||||||
return this.ldap.loginLabel;
|
return this.ldap.loginLabel;
|
||||||
},
|
},
|
||||||
|
isSamlLoginEnabled(): boolean {
|
||||||
|
return this.saml.loginEnabled;
|
||||||
|
},
|
||||||
|
samlLoginLabel(): string {
|
||||||
|
return this.saml.loginLabel;
|
||||||
|
},
|
||||||
showSetupPage(): boolean {
|
showSetupPage(): boolean {
|
||||||
return this.userManagement.showSetupOnFirstLoad === true;
|
return this.userManagement.showSetupOnFirstLoad === true;
|
||||||
},
|
},
|
||||||
|
@ -168,8 +178,10 @@ export const useSettingsStore = defineStore(STORES.SETTINGS, {
|
||||||
this.userManagement.smtpSetup = settings.userManagement.smtpSetup;
|
this.userManagement.smtpSetup = settings.userManagement.smtpSetup;
|
||||||
this.api = settings.publicApi;
|
this.api = settings.publicApi;
|
||||||
this.onboardingCallPromptEnabled = settings.onboardingCallPromptEnabled;
|
this.onboardingCallPromptEnabled = settings.onboardingCallPromptEnabled;
|
||||||
this.ldap.loginEnabled = settings.ldap.loginEnabled;
|
this.ldap.loginEnabled = settings.sso.ldap.loginEnabled;
|
||||||
this.ldap.loginLabel = settings.ldap.loginLabel;
|
this.ldap.loginLabel = settings.sso.ldap.loginLabel;
|
||||||
|
this.saml.loginEnabled = settings.sso.saml.loginEnabled;
|
||||||
|
this.saml.loginLabel = settings.sso.saml.loginLabel;
|
||||||
},
|
},
|
||||||
async getSettings(): Promise<void> {
|
async getSettings(): Promise<void> {
|
||||||
const rootStore = useRootStore();
|
const rootStore = useRootStore();
|
||||||
|
|
Loading…
Reference in a new issue