CB-3740 fix: handle authentication errors (#1844)

* CB-3740 fix: handle authentication errors

* CB-3740 chore: add localization
This commit is contained in:
Alexey
2023-07-26 20:13:44 +03:00
committed by GitHub
parent f41effd655
commit 8fba6107b2
9 changed files with 83 additions and 9 deletions
@@ -38,6 +38,7 @@ export interface ILoginOptions {
@injectable()
export class UserInfoResource extends CachedDataResource<UserInfo | null, void, UserInfoIncludes> {
readonly onUserChange: ISyncExecutor<string>;
readonly onException: ISyncExecutor<Error>;
get authRole(): ELMRole | undefined {
return this.data?.authRole as ELMRole | undefined;
@@ -56,6 +57,7 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
super(() => null, undefined, ['customIncludeOriginDetails', 'includeConfigurationParameters']);
this.onUserChange = new SyncExecutor();
this.onException = new SyncExecutor();
this.sync(
sessionResource,
@@ -234,12 +236,20 @@ export class UserInfoResource extends CachedDataResource<UserInfo | null, void,
}
protected async loader(key: void, includes?: ReadonlyArray<string>): Promise<UserInfo | null> {
const { user } = await this.graphQLService.sdk.getActiveUser({
...this.getDefaultIncludes(),
...this.getIncludesMap(key, includes),
});
try {
const { user } = await this.graphQLService.sdk.getActiveUser({
...this.getDefaultIncludes(),
...this.getIncludesMap(key, includes),
});
return (user as UserInfo | null) || null;
return (user as UserInfo | null) || null;
} catch (exception: any) {
if (this.onException.isEmpty) {
throw exception;
}
this.onException.execute(exception);
return null;
}
}
protected setData(data: UserInfo | null): void {
@@ -12,9 +12,14 @@ import type { IExecutorHandler } from './IExecutorHandler';
import type { ExecutorDataFilter, ExecutorDataMap, IChainLink, IExecutorHandlersCollection } from './IExecutorHandlersCollection';
export class ExecutorHandlersCollection<T = unknown, TResult = any | Promise<any>> implements IExecutorHandlersCollection<T, TResult> {
handlers: Array<IExecutorHandler<T, TResult>> = [];
postHandlers: Array<IExecutorHandler<T, TResult>> = [];
chain: Array<IChainLink<T, TResult>> = [];
handlers: Array<IExecutorHandler<T, TResult>>;
postHandlers: Array<IExecutorHandler<T, TResult>>;
chain: Array<IChainLink<T, TResult>>;
get isEmpty(): boolean {
return this.handlers.length === 0 && this.postHandlers.length === 0 && this.chain.length === 0;
}
readonly contextCreators: Map<IContextLoader<any, T>, IContextLoader<any, T>>;
readonly collections: Array<IExecutorHandlersCollection<T, TResult>>;
protected initialDataGetter: (() => T) | null;
@@ -25,6 +30,9 @@ export class ExecutorHandlersCollection<T = unknown, TResult = any | Promise<any
this.contextCreators = new Map();
this.collections = [];
this.initialDataGetter = null;
this.handlers = [];
this.postHandlers = [];
this.chain = [];
makeObservable<this, 'links'>(this, {
handlers: observable.shallow,
@@ -20,6 +20,7 @@ export interface IChainLink<T, TResult> {
}
export interface IExecutorHandlersCollection<T = unknown, TResult = any | Promise<any>> {
readonly isEmpty: boolean;
readonly handlers: Array<IExecutorHandler<T, TResult>>;
readonly postHandlers: Array<IExecutorHandler<T, TResult>>;
readonly chain: Array<IChainLink<T, TResult>>;
@@ -0,0 +1,38 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2023 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { UserInfoResource } from '@cloudbeaver/core-authentication';
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { CommonDialogService, ConfirmationDialog, DialogueStateResult } from '@cloudbeaver/core-dialogs';
import { NotificationService } from '@cloudbeaver/core-events';
@injectable()
export class UserLoadingErrorDialogBootstrap extends Bootstrap {
constructor(
private readonly userInfoResource: UserInfoResource,
private readonly commonDialogService: CommonDialogService,
private readonly notificationService: NotificationService,
) {
super();
userInfoResource.onException.addHandler(this.handleException.bind(this));
}
register(): void | Promise<void> {}
load(): void | Promise<void> {}
private async handleException(exception: Error) {
this.notificationService.logException(exception, 'plugin_authentication_user_loading_error');
const result = await this.commonDialogService.open(ConfirmationDialog, {
title: 'plugin_authentication_loading_error_dialog_title',
message: 'plugin_authentication_loading_error_dialog_message',
});
if (result === DialogueStateResult.Resolved) {
await this.userInfoResource.logout();
}
}
}
@@ -31,4 +31,8 @@ export default [
['authentication_user_login_cant_be_used', 'Sorry, that name cannot be used'],
['authentication_user_icon_tooltip', 'User'],
['authentication_team_icon_tooltip', 'Team'],
['plugin_authentication_user_loading_error', "Can't load user data"],
['plugin_authentication_loading_error_dialog_title', 'Authentication error'],
['plugin_authentication_loading_error_dialog_message', 'An error occurred while loading user data. Do you want to logout?'],
];
@@ -22,4 +22,8 @@ export default [
['authentication_user_login_already_exists', 'Esiste già un utente con quel nome'],
['authentication_user_login_cant_be_used', 'Quel nome non può essere usato'],
['authentication_user_icon_tooltip', 'Utente'],
['plugin_authentication_user_loading_error', "Can't load user data"],
['plugin_authentication_loading_error_dialog_title', 'Authentication error'],
['plugin_authentication_loading_error_dialog_message', 'An error occurred while loading user data. Do you want to logout?'],
];
@@ -31,4 +31,8 @@ export default [
['authentication_user_login_cant_be_used', 'Данное имя нельзя использовать'],
['authentication_user_icon_tooltip', 'Пользователь'],
['authentication_team_icon_tooltip', 'Команда'],
['plugin_authentication_user_loading_error', 'Не удалось загрузить данные пользователя'],
['plugin_authentication_loading_error_dialog_title', 'Ошибка аутентификации'],
['plugin_authentication_loading_error_dialog_message', 'Произошла ошибка при загрузке данных пользователя. Выйти?'],
];
@@ -28,4 +28,8 @@ export default [
['authentication_user_login_already_exists', '同名用户已存在'],
['authentication_user_login_cant_be_used', '抱歉,不能使用该名称'],
['authentication_user_icon_tooltip', '用户'],
['plugin_authentication_user_loading_error', "Can't load user data"],
['plugin_authentication_loading_error_dialog_title', 'Authentication error'],
['plugin_authentication_loading_error_dialog_message', 'An error occurred while loading user data. Do you want to logout?'],
];
@@ -11,11 +11,12 @@ import { AuthenticationLocaleService } from './AuthenticationLocaleService';
import { AuthenticationService } from './AuthenticationService';
import { AuthDialogService } from './Dialog/AuthDialogService';
import { PluginBootstrap } from './PluginBootstrap';
import { UserLoadingErrorDialogBootstrap } from './UserLoadingErrorDialogBootstrap';
export const manifest: PluginManifest = {
info: {
name: 'Plugin Authentication',
},
providers: [AuthenticationService, AuthDialogService, PluginBootstrap, AuthenticationLocaleService],
providers: [AuthenticationService, AuthDialogService, PluginBootstrap, AuthenticationLocaleService, UserLoadingErrorDialogBootstrap],
};