feat(editor): SSO setup (#5736)
* feat(editor): SSO settings page * feat(editor): SSO settings page * feat(editor): SSO settings page * feat(editor): SSO settings page * feat(editor): SSO settings page * feat(editor): SSO settings page * Merge remote-tracking branch 'origin/master' into pay-170-sso-set-up-page # Conflicts: # packages/cli/src/sso/saml/routes/saml.controller.ee.ts * feat(editor): Prevent SSO settings page route * feat(editor): some UI improvements * fix(editor): SSO settings saml config optional chaining * fix return values saml controller * fix(editor): drop dompurify * fix(editor): save xml as is * return authenticationMethod with settings * fix(editor): add missing prop to server * chore(editor): code formatting * fix ldap/saml enable toggle endpoint * fix missing import * prevent faulty ldap setting from breaking startup * remove sso fake-door from users page * fix(editor): update SSO settings route permissions + unit testing * fix(editor): update vite config for test * fix(editor): add paddings to SSO settings page buttons, add translation * fix(editor): fix saml unit test * fix(core): Improve saml test connection function (#5899) improve-saml-test-connection return --------- Co-authored-by: Michael Auerswald <michael.auerswald@gmail.com> Co-authored-by: Romain Minaud <romain.minaud@gmail.com>
This commit is contained in:
174
packages/editor-ui/src/views/SettingsSso.vue
Normal file
174
packages/editor-ui/src/views/SettingsSso.vue
Normal file
@@ -0,0 +1,174 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, onBeforeMount } from 'vue';
|
||||
import { Notification } from 'element-ui';
|
||||
import { useSSOStore } from '@/stores/sso';
|
||||
import { i18n as locale } from '@/plugins/i18n';
|
||||
import CopyInput from '@/components/CopyInput.vue';
|
||||
|
||||
const ssoStore = useSSOStore();
|
||||
|
||||
const ssoActivatedLabel = computed(() =>
|
||||
ssoStore.isSamlLoginEnabled
|
||||
? locale.baseText('settings.sso.activated')
|
||||
: locale.baseText('settings.sso.deactivated'),
|
||||
);
|
||||
const ssoSettingsSaved = ref(false);
|
||||
const metadata = ref();
|
||||
const redirectUrl = ref();
|
||||
const entityId = ref();
|
||||
|
||||
const getSamlConfig = async () => {
|
||||
const config = await ssoStore.getSamlConfig();
|
||||
entityId.value = config?.entityID;
|
||||
redirectUrl.value = config?.returnUrl;
|
||||
metadata.value = config?.metadata;
|
||||
ssoSettingsSaved.value = !!config?.metadata;
|
||||
};
|
||||
|
||||
const onSave = async () => {
|
||||
try {
|
||||
await ssoStore.saveSamlConfig({ metadata: metadata.value });
|
||||
await getSamlConfig();
|
||||
} catch (error) {
|
||||
Notification.error({
|
||||
title: 'Error',
|
||||
message: error.message,
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onTest = async () => {
|
||||
try {
|
||||
const url = await ssoStore.testSamlConfig();
|
||||
window.open(url, '_blank');
|
||||
} catch (error) {
|
||||
Notification.error({
|
||||
title: 'Error',
|
||||
message: error.message,
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
try {
|
||||
await getSamlConfig();
|
||||
} catch (error) {
|
||||
Notification.error({
|
||||
title: 'Error',
|
||||
message: error.message,
|
||||
position: 'bottom-right',
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<n8n-heading size="2xlarge">{{ locale.baseText('settings.sso.title') }}</n8n-heading>
|
||||
<div :class="$style.top">
|
||||
<n8n-heading size="medium">{{ locale.baseText('settings.sso.subtitle') }}</n8n-heading>
|
||||
<n8n-tooltip :disabled="ssoStore.isSamlLoginEnabled">
|
||||
<template #content>
|
||||
<span>
|
||||
{{ locale.baseText('settings.sso.activation.tooltip') }}
|
||||
</span>
|
||||
</template>
|
||||
<el-switch
|
||||
v-model="ssoStore.isSamlLoginEnabled"
|
||||
:disabled="!ssoSettingsSaved"
|
||||
:class="$style.switch"
|
||||
:inactive-text="ssoActivatedLabel"
|
||||
/>
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
<n8n-info-tip>
|
||||
<i18n :class="$style.count" path="settings.sso.info">
|
||||
<template #link>
|
||||
<a href="https://docs.n8n.io/user-management/sso/" target="_blank">
|
||||
{{ locale.baseText('settings.sso.info.link') }}
|
||||
</a>
|
||||
</template>
|
||||
</i18n>
|
||||
</n8n-info-tip>
|
||||
<div :class="$style.group">
|
||||
<label>{{ locale.baseText('settings.sso.settings.redirectUrl.label') }}</label>
|
||||
<CopyInput
|
||||
:class="$style.copyInput"
|
||||
:value="redirectUrl"
|
||||
:copy-button-text="locale.baseText('generic.clickToCopy')"
|
||||
:toast-title="locale.baseText('settings.sso.settings.redirectUrl.copied')"
|
||||
/>
|
||||
<small>{{ locale.baseText('settings.sso.settings.redirectUrl.help') }}</small>
|
||||
</div>
|
||||
<div :class="$style.group">
|
||||
<label>{{ locale.baseText('settings.sso.settings.entityId.label') }}</label>
|
||||
<CopyInput
|
||||
:class="$style.copyInput"
|
||||
:value="entityId"
|
||||
:copy-button-text="locale.baseText('generic.clickToCopy')"
|
||||
:toast-title="locale.baseText('settings.sso.settings.entityId.copied')"
|
||||
/>
|
||||
<small>{{ locale.baseText('settings.sso.settings.entityId.help') }}</small>
|
||||
</div>
|
||||
<div :class="$style.group">
|
||||
<label>{{ locale.baseText('settings.sso.settings.ips.label') }}</label>
|
||||
<n8n-input v-model="metadata" type="textarea" />
|
||||
<small>{{ locale.baseText('settings.sso.settings.ips.help') }}</small>
|
||||
</div>
|
||||
<div :class="$style.buttons">
|
||||
<n8n-button :disabled="!ssoSettingsSaved" type="tertiary" @click="onTest">
|
||||
{{ locale.baseText('settings.sso.settings.test') }}
|
||||
</n8n-button>
|
||||
<n8n-button :disabled="!metadata" @click="onSave">
|
||||
{{ locale.baseText('settings.sso.settings.save') }}
|
||||
</n8n-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-2xl) 0 var(--spacing-xl);
|
||||
}
|
||||
|
||||
.switch {
|
||||
span {
|
||||
font-size: var(--font-size-2xs);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--color-text-light);
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding: var(--spacing-2xl) 0 var(--spacing-3xl);
|
||||
|
||||
button {
|
||||
margin: 0 var(--spacing-s) 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
padding: var(--spacing-xl) 0 0;
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
font-size: var(--font-size-s);
|
||||
font-weight: var(--font-weight-bold);
|
||||
padding: 0 0 var(--spacing-2xs);
|
||||
}
|
||||
|
||||
small {
|
||||
display: block;
|
||||
padding: var(--spacing-2xs) 0 0;
|
||||
font-size: var(--font-size-2xs);
|
||||
color: var(--color-text-base);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -47,13 +47,6 @@
|
||||
@copyInviteLink="onCopyInviteLink"
|
||||
/>
|
||||
</div>
|
||||
<feature-coming-soon
|
||||
v-for="fakeDoorFeature in fakeDoorFeatures"
|
||||
:key="fakeDoorFeature.id"
|
||||
:featureId="fakeDoorFeature.id"
|
||||
class="pb-3xl"
|
||||
showTitle
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -61,8 +54,7 @@
|
||||
import { EnterpriseEditionFeature, INVITE_USER_MODAL_KEY, VIEWS } from '@/constants';
|
||||
|
||||
import PageAlert from '../components/PageAlert.vue';
|
||||
import FeatureComingSoon from '@/components/FeatureComingSoon.vue';
|
||||
import { IFakeDoor, IUser, IUserListAction } from '@/Interface';
|
||||
import { IUser, IUserListAction } from '@/Interface';
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { showMessage } from '@/mixins/showMessage';
|
||||
import { copyPaste } from '@/mixins/copyPaste';
|
||||
@@ -77,7 +69,6 @@ export default mixins(showMessage, copyPaste).extend({
|
||||
name: 'SettingsUsersView',
|
||||
components: {
|
||||
PageAlert,
|
||||
FeatureComingSoon,
|
||||
},
|
||||
async mounted() {
|
||||
if (!this.usersStore.showUMSetupWarning) {
|
||||
@@ -107,9 +98,6 @@ export default mixins(showMessage, copyPaste).extend({
|
||||
},
|
||||
];
|
||||
},
|
||||
fakeDoorFeatures(): IFakeDoor[] {
|
||||
return this.uiStore.getFakeDoorByLocation('settings/users');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
redirectToSetup() {
|
||||
|
||||
Reference in New Issue
Block a user