diff --git a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java index 4b68f9d8ae..b96cb165e3 100644 --- a/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java +++ b/server/bundles/io.cloudbeaver.service.security/src/io/cloudbeaver/service/security/CBEmbeddedSecurityController.java @@ -1034,6 +1034,10 @@ public void updateTeam(String teamId, String name, String description) throws DB @Override public void deleteTeam(String teamId, boolean force) throws DBCException { + String defaultUsersTeam = application.getAppConfiguration().getDefaultUserTeam(); + if (CommonUtils.isNotEmpty(defaultUsersTeam) && defaultUsersTeam.equals(teamId)) { + throw new DBCException("Default users team cannot be deleted"); + } try (Connection dbCon = database.openConnection()) { if (!force) { try (PreparedStatement dbStat = dbCon.prepareStatement( diff --git a/webapp/packages/core-authentication/src/UsersResource.ts b/webapp/packages/core-authentication/src/UsersResource.ts index 8d0692960e..9963f6a32b 100644 --- a/webapp/packages/core-authentication/src/UsersResource.ts +++ b/webapp/packages/core-authentication/src/UsersResource.ts @@ -52,6 +52,7 @@ export const UsersResourceNewUsers = resourceKeyListAlias('@users-resource/new-u interface UserCreateOptions { userId: string; + authRole?: string; } @injectable() @@ -131,9 +132,10 @@ export class UsersResource extends CachedMapResource { + async create({ userId, authRole }: UserCreateOptions): Promise { const { user } = await this.graphQLService.sdk.createUser({ userId, + authRole, enabled: false, ...this.getDefaultIncludes(), ...this.getIncludesMap(userId), diff --git a/webapp/packages/core-ui/src/Form/FormState.ts b/webapp/packages/core-ui/src/Form/FormState.ts index 20ec2bae0a..800a52e727 100644 --- a/webapp/packages/core-ui/src/Form/FormState.ts +++ b/webapp/packages/core-ui/src/Form/FormState.ts @@ -10,7 +10,7 @@ import { action, makeObservable, observable } from 'mobx'; import { dataContextAddDIProvider, type IDataContext, TempDataContext } from '@cloudbeaver/core-data-context'; import type { App } from '@cloudbeaver/core-di'; import type { ENotificationType } from '@cloudbeaver/core-events'; -import { Executor, IExecutionContextProvider, type IExecutor } from '@cloudbeaver/core-executor'; +import { Executor, ExecutorInterrupter, IExecutionContextProvider, type IExecutor } from '@cloudbeaver/core-executor'; import { isLoadableStateHasException, MetadataMap, uuid } from '@cloudbeaver/core-utils'; import { DATA_CONTEXT_LOADABLE_STATE, loadableStateContext } from '@cloudbeaver/core-view'; @@ -193,7 +193,11 @@ export class FormState implements IFormState { async save(): Promise { try { this.isDisabled = true; - await this.submitTask.execute(this); + const context = await this.submitTask.execute(this); + + if (ExecutorInterrupter.isInterrupted(context)) { + return false; + } this.exception = null; return true; diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/DATA_CONTEXT_USER_FORM_INFO_PART.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/DATA_CONTEXT_USER_FORM_INFO_PART.ts index 930a29ba2c..c2a543d87e 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/DATA_CONTEXT_USER_FORM_INFO_PART.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/DATA_CONTEXT_USER_FORM_INFO_PART.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { UsersResource } from '@cloudbeaver/core-authentication'; +import { AuthRolesResource, UsersResource } from '@cloudbeaver/core-authentication'; import { createDataContext, DATA_CONTEXT_DI_PROVIDER } from '@cloudbeaver/core-data-context'; import { ServerConfigResource } from '@cloudbeaver/core-root'; import { DATA_CONTEXT_FORM_STATE } from '@cloudbeaver/core-ui'; @@ -18,6 +18,7 @@ export const DATA_CONTEXT_USER_FORM_INFO_PART = createDataContext; teams: string[]; + + authRole: string; // used in TE product } diff --git a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts index 0bc19ff03e..c32dafb78f 100644 --- a/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts +++ b/webapp/packages/plugin-authentication-administration/src/Administration/Users/UserForm/Info/UserFormInfoPart.ts @@ -7,7 +7,7 @@ */ import { observable } from 'mobx'; -import type { AdminUser, UsersResource } from '@cloudbeaver/core-authentication'; +import type { AdminUser, AuthRolesResource, UsersResource } from '@cloudbeaver/core-authentication'; import type { IExecutionContextProvider } from '@cloudbeaver/core-executor'; import { getCachedDataResourceLoaderState } from '@cloudbeaver/core-resource'; import type { ServerConfigResource } from '@cloudbeaver/core-root'; @@ -23,6 +23,7 @@ const DEFAULT_ENABLED = true; export class UserFormInfoPart extends FormPart { constructor( + private readonly authRolesResource: AuthRolesResource, private readonly serverConfigResource: ServerConfigResource, formState: AdministrationUserFormState, private readonly usersResource: UsersResource, @@ -33,6 +34,7 @@ export class UserFormInfoPart extends FormPart 0) { + const authRole = getTransformedAuthRole(this.state.authRole); + if (!authRole || !this.authRolesResource.data.includes(authRole)) { + validation.error('authentication_user_role_not_set'); + } + } } protected override configure() { const loadableStateContext = this.formState.dataContext.get(DATA_CONTEXT_LOADABLE_STATE); - loadableStateContext.getState('user-info', () => [getCachedDataResourceLoaderState(this.serverConfigResource, undefined)]); + loadableStateContext.getState('user-info', () => [ + getCachedDataResourceLoaderState(this.serverConfigResource, undefined), + getCachedDataResourceLoaderState(this.authRolesResource, undefined), + ]); } private async updateCredentials() { @@ -122,6 +137,17 @@ export class UserFormInfoPart extends FormPart 0) { + const authRole = getTransformedAuthRole(this.state.authRole); + const user = this.usersResource.get(this.state.userId); + + if (!isValuesEqual(authRole, user?.authRole, '')) { + await this.usersResource.setAuthRole(this.state.userId, authRole, true); + } + } + } + private async updateTeams() { let grantedTeams: string[] = []; @@ -179,10 +205,16 @@ export class UserFormInfoPart extends FormPart