feat: Add manual login option and password reset link for SSO (#6328)
* consolidate IUserSettings in workflow and add allowSSOManualLogin * add pw reset link to owners ui
This commit is contained in:
committed by
GitHub
parent
8f0ff460b1
commit
77e3f1551d
@@ -33,6 +33,7 @@ import type {
|
||||
IN8nUISettings,
|
||||
IUserManagementSettings,
|
||||
WorkflowSettings,
|
||||
IUserSettings,
|
||||
} from 'n8n-workflow';
|
||||
import type { SignInType } from './constants';
|
||||
import type {
|
||||
@@ -561,12 +562,7 @@ export interface IUserResponse {
|
||||
personalizationAnswers?: IPersonalizationSurveyVersions | null;
|
||||
isPending: boolean;
|
||||
signInType?: SignInType;
|
||||
settings?: {
|
||||
isOnboarded?: boolean;
|
||||
showUserActivationSurvey?: boolean;
|
||||
firstSuccessfulWorkflowId?: string;
|
||||
userActivated?: boolean;
|
||||
};
|
||||
settings?: IUserSettings;
|
||||
}
|
||||
|
||||
export interface CurrentUserResponse extends IUserResponse {
|
||||
|
||||
@@ -105,7 +105,15 @@ export async function updateCurrentUserSettings(
|
||||
context: IRestApiContext,
|
||||
settings: IUserResponse['settings'],
|
||||
): Promise<IUserResponse['settings']> {
|
||||
return makeRestApiRequest(context, 'PATCH', '/me/settings', settings);
|
||||
return makeRestApiRequest(context, 'PATCH', '/me/settings', settings as IDataObject);
|
||||
}
|
||||
|
||||
export async function updateOtherUserSettings(
|
||||
context: IRestApiContext,
|
||||
userId: string,
|
||||
settings: IUserResponse['settings'],
|
||||
): Promise<IUserResponse['settings']> {
|
||||
return makeRestApiRequest(context, 'PATCH', `/users/${userId}/settings`, settings as IDataObject);
|
||||
}
|
||||
|
||||
export async function updateCurrentUserPassword(
|
||||
@@ -144,6 +152,13 @@ export async function getInviteLink(
|
||||
return makeRestApiRequest(context, 'GET', `/users/${id}/invite-link`);
|
||||
}
|
||||
|
||||
export async function getPasswordResetLink(
|
||||
context: IRestApiContext,
|
||||
{ id }: { id: string },
|
||||
): Promise<{ link: string }> {
|
||||
return makeRestApiRequest(context, 'GET', `/users/${id}/password-reset-link`);
|
||||
}
|
||||
|
||||
export async function submitPersonalizationSurvey(
|
||||
context: IRestApiContext,
|
||||
params: IPersonalizationLatestVersion,
|
||||
|
||||
@@ -1169,6 +1169,9 @@
|
||||
"settings.users.actions.delete": "Delete User",
|
||||
"settings.users.actions.reinvite": "Resend Invite",
|
||||
"settings.users.actions.copyInviteLink": "Copy Invite Link",
|
||||
"settings.users.actions.copyPasswordResetLink": "Copy Password Reset Link",
|
||||
"settings.users.actions.allowSSOManualLogin": "Allow Manual Login",
|
||||
"settings.users.actions.disallowSSOManualLogin": "Disallow Manual Login",
|
||||
"settings.users.deleteWorkflowsAndCredentials": "Delete their workflows and credentials",
|
||||
"settings.users.emailInvitesSent": "An invite email was sent to {emails}",
|
||||
"settings.users.emailInvitesSentError": "Could not invite {emails}",
|
||||
@@ -1187,6 +1190,12 @@
|
||||
"settings.users.inviteXUser.inviteUrl": "Create {count} invite links",
|
||||
"settings.users.inviteUrlCreated": "Invite link copied to clipboard",
|
||||
"settings.users.inviteUrlCreated.message": "Send the invite link to your invitee for activation",
|
||||
"settings.users.passwordResetUrlCreated": "Password reset link copied to clipboard",
|
||||
"settings.users.passwordResetUrlCreated.message": "Send the reset link to your user for them to reset their password",
|
||||
"settings.users.allowSSOManualLogin": "Manual Login Allowed",
|
||||
"settings.users.allowSSOManualLogin.message": "User can now login manually and through SSO",
|
||||
"settings.users.disallowSSOManualLogin": "Manual Login Disallowed",
|
||||
"settings.users.disallowSSOManualLogin.message": "User must now login through SSO only",
|
||||
"settings.users.multipleInviteUrlsCreated": "Invite links created",
|
||||
"settings.users.multipleInviteUrlsCreated.message": "Send the invite links to your invitees for activation",
|
||||
"settings.users.newEmailsToInvite": "New User Email Addresses",
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
changePassword,
|
||||
deleteUser,
|
||||
getInviteLink,
|
||||
getPasswordResetLink,
|
||||
getUsers,
|
||||
inviteUsers,
|
||||
login,
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
updateCurrentUser,
|
||||
updateCurrentUserPassword,
|
||||
updateCurrentUserSettings,
|
||||
updateOtherUserSettings,
|
||||
validatePasswordToken,
|
||||
validateSignupToken,
|
||||
} from '@/api/users';
|
||||
@@ -251,6 +253,19 @@ export const useUsersStore = defineStore(STORES.USERS, {
|
||||
this.addUsers([this.currentUser]);
|
||||
}
|
||||
},
|
||||
async updateOtherUserSettings(
|
||||
userId: string,
|
||||
settings: IUserResponse['settings'],
|
||||
): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
const updatedSettings = await updateOtherUserSettings(
|
||||
rootStore.getRestApiContext,
|
||||
userId,
|
||||
settings,
|
||||
);
|
||||
this.users[userId].settings = updatedSettings;
|
||||
this.addUsers([this.users[userId]]);
|
||||
},
|
||||
async updateCurrentUserPassword({
|
||||
password,
|
||||
currentPassword,
|
||||
@@ -288,6 +303,10 @@ export const useUsersStore = defineStore(STORES.USERS, {
|
||||
const rootStore = useRootStore();
|
||||
return getInviteLink(rootStore.getRestApiContext, params);
|
||||
},
|
||||
async getUserPasswordResetLink(params: { id: string }): Promise<{ link: string }> {
|
||||
const rootStore = useRootStore();
|
||||
return getPasswordResetLink(rootStore.getRestApiContext, params);
|
||||
},
|
||||
async submitPersonalizationSurvey(results: IPersonalizationLatestVersion): Promise<void> {
|
||||
const rootStore = useRootStore();
|
||||
await submitPersonalizationSurvey(rootStore.getRestApiContext, results);
|
||||
|
||||
@@ -50,9 +50,13 @@
|
||||
:actions="usersListActions"
|
||||
:users="usersStore.allUsers"
|
||||
:currentUserId="usersStore.currentUserId"
|
||||
:isSamlLoginEnabled="ssoStore.isSamlLoginEnabled"
|
||||
@delete="onDelete"
|
||||
@reinvite="onReinvite"
|
||||
@copyInviteLink="onCopyInviteLink"
|
||||
@copyPasswordResetLink="onCopyPasswordResetLink"
|
||||
@allowSSOManualLogin="onAllowSSOManualLogin"
|
||||
@disallowSSOManualLogin="onDisallowSSOManualLogin"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -106,6 +110,22 @@ export default defineComponent({
|
||||
label: this.$locale.baseText('settings.users.actions.delete'),
|
||||
value: 'delete',
|
||||
},
|
||||
{
|
||||
label: this.$locale.baseText('settings.users.actions.copyPasswordResetLink'),
|
||||
value: 'copyPasswordResetLink',
|
||||
},
|
||||
{
|
||||
label: this.$locale.baseText('settings.users.actions.allowSSOManualLogin'),
|
||||
value: 'allowSSOManualLogin',
|
||||
guard: (user) =>
|
||||
this.settingsStore.isSamlLoginEnabled && !user.settings?.allowSSOManualLogin,
|
||||
},
|
||||
{
|
||||
label: this.$locale.baseText('settings.users.actions.disallowSSOManualLogin'),
|
||||
value: 'disallowSSOManualLogin',
|
||||
guard: (user) =>
|
||||
this.settingsStore.isSamlLoginEnabled && user.settings?.allowSSOManualLogin === true,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
@@ -152,6 +172,44 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
},
|
||||
async onCopyPasswordResetLink(userId: string) {
|
||||
const user = this.usersStore.getUserById(userId) as IUser | null;
|
||||
if (user) {
|
||||
const url = await this.usersStore.getUserPasswordResetLink(user);
|
||||
this.copyToClipboard(url.link);
|
||||
|
||||
this.showToast({
|
||||
type: 'success',
|
||||
title: this.$locale.baseText('settings.users.passwordResetUrlCreated'),
|
||||
message: this.$locale.baseText('settings.users.passwordResetUrlCreated.message'),
|
||||
});
|
||||
}
|
||||
},
|
||||
async onAllowSSOManualLogin(userId: string) {
|
||||
const user = this.usersStore.getUserById(userId) as IUser | null;
|
||||
if (user?.settings) {
|
||||
user.settings.allowSSOManualLogin = true;
|
||||
await this.usersStore.updateOtherUserSettings(userId, user.settings);
|
||||
|
||||
this.showToast({
|
||||
type: 'success',
|
||||
title: this.$locale.baseText('settings.users.allowSSOManualLogin'),
|
||||
message: this.$locale.baseText('settings.users.allowSSOManualLogin.message'),
|
||||
});
|
||||
}
|
||||
},
|
||||
async onDisallowSSOManualLogin(userId: string) {
|
||||
const user = this.usersStore.getUserById(userId) as IUser | null;
|
||||
if (user?.settings) {
|
||||
user.settings.allowSSOManualLogin = false;
|
||||
await this.usersStore.updateOtherUserSettings(userId, user.settings);
|
||||
this.showToast({
|
||||
type: 'success',
|
||||
title: this.$locale.baseText('settings.users.disallowSSOManualLogin'),
|
||||
message: this.$locale.baseText('settings.users.disallowSSOManualLogin.message'),
|
||||
});
|
||||
}
|
||||
},
|
||||
goToUpgrade() {
|
||||
this.uiStore.goToUpgrade('users', 'upgrade-users');
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user