Skip to content

Commit

Permalink
Merge branch 'CB-5710-aws-integration-for-cloud-explorer-and-storage'…
Browse files Browse the repository at this point in the history
… of https://github.com/dbeaver/cloudbeaver into CB-5710-aws-integration-for-cloud-explorer-and-storage
  • Loading branch information
devnaumov committed Oct 9, 2024
2 parents 8ab9b2e + 97137c2 commit 1688a7e
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 82 deletions.
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
"label": "Build CE",
"type": "shell",
"windows": {
"command": "./build-sqlite.bat"
"command": "./build.bat"
},
"osx": {
"command": "./build-sqlite.sh"
"command": "./build.sh"
},
"options": {
"cwd": "${workspaceFolder}/deploy"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public List<BaseProjectImpl> getProjects() {
@Nullable
@Override
public BaseProjectImpl getProject(@NotNull String projectName) {
if (globalProject.getId().equals(projectName)) {
if (globalProject != null && globalProject.getId().equals(projectName)) {
return globalProject;
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,100 +19,162 @@
import io.cloudbeaver.WebSessionGlobalProjectImpl;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.service.security.SMUtils;
import io.cloudbeaver.utils.WebAppUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMObjectPermissionsGrant;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class WSObjectPermissionUpdatedEventHandler extends WSDefaultEventHandler<WSObjectPermissionEvent> {
private static final Log log = Log.getLog(WSObjectPermissionUpdatedEventHandler.class);

@Override
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSObjectPermissionEvent event) {
try {
public void handleEvent(@NotNull WSObjectPermissionEvent event) {
String objectId = event.getObjectId();
Consumer<BaseWebSession> runnable = switch (event.getSmObjectType()) {
case project:
yield getUpdateUserProjectsInfoConsumer(event, objectId);
case datasource:
try {
SMAdminController smController = CBApplication.getInstance().getSecurityController();
Set<String> dataSourcePermissions = smController.getObjectPermissionGrants(event.getObjectId(), event.getSmObjectType())
.stream()
.map(SMObjectPermissionsGrant::getSubjectId).collect(Collectors.toSet());
yield getUpdateUserDataSourcesInfoConsumer(event, objectId, dataSourcePermissions);
} catch (DBException e) {
log.error("Error getting permissions for data source " + objectId, e);
yield null;
}
};
if (runnable == null) {
return;
}
log.debug(event.getTopicId() + " event handled");
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
for (var activeUserSession : allSessions) {
if (!isAcceptableInSession(activeUserSession, event)) {
log.debug("Cannot handle %s event '%s' in session %s".formatted(
event.getTopicId(),
event.getId(),
activeUserSession.getSessionId()
));
continue;
}
log.debug("%s event '%s' handled".formatted(event.getTopicId(), event.getId()));
runnable.accept(activeUserSession);
}
}

@NotNull
private Consumer<BaseWebSession> getUpdateUserDataSourcesInfoConsumer(
@NotNull WSObjectPermissionEvent event,
@NotNull String dataSourceId,
@NotNull Set<String> dataSourcePermissions
) {
return (activeUserSession) -> {
// we have accessible data sources only in web session
if (event.getSmObjectType() == SMObjectType.datasource && !(activeUserSession instanceof WebSession)) {
// admins already have access for all shared connections
if (!(activeUserSession instanceof WebSession webSession) || SMUtils.isAdmin(webSession)) {
return;
}
var objectId = event.getObjectId();

boolean isAccessibleNow;
switch (event.getSmObjectType()) {
case project:
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
var accessibleProjectIds = activeUserSession.getUserContext().getAccessibleProjectIds();
if (accessibleProjectIds.contains(event.getObjectId())) {
return;
}
activeUserSession.addSessionProject(objectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.create(
event.getSessionId(),
event.getUserId(),
objectId
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
activeUserSession.removeSessionProject(objectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.delete(
event.getSessionId(),
event.getUserId(),
objectId
)
);
}
break;
case datasource:
var webSession = (WebSession) activeUserSession;
var dataSources = List.of(objectId);
if (!isAcceptableInSession(webSession, event)) {
return;
}
var user = activeUserSession.getUserContext().getUser();
var userSubjects = new HashSet<>(Set.of(user.getTeams()));
userSubjects.add(user.getUserId());
boolean shouldBeAccessible = dataSourcePermissions.stream().anyMatch(userSubjects::contains);
List<String> dataSources = List.of(dataSourceId);
WebSessionGlobalProjectImpl project = webSession.getGlobalProject();
if (project == null) {
log.error("Project " + WebAppUtils.getGlobalProjectId() +
" is not found in session " + activeUserSession.getSessionId());
return;
}
boolean isAccessibleNow = project.findWebConnectionInfo(dataSourceId) != null;
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
if (isAccessibleNow || !shouldBeAccessible) {
return;
}
project.addAccessibleConnectionToCache(dataSourceId);
webSession.addSessionEvent(
WSDataSourceEvent.create(
event.getSessionId(),
event.getUserId(),
project.getId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
if (!isAccessibleNow || shouldBeAccessible) {
return;
}
project.removeAccessibleConnectionFromCache(dataSourceId);
webSession.addSessionEvent(
WSDataSourceEvent.delete(
event.getSessionId(),
event.getUserId(),
project.getId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
}
};
}

WebSessionGlobalProjectImpl project = webSession.getGlobalProject();
if (project == null) {
log.error("Project " + WebAppUtils.getGlobalProjectId() +
" is not found in session " + activeUserSession.getSessionId());
@NotNull
private Consumer<BaseWebSession> getUpdateUserProjectsInfoConsumer(
@NotNull WSObjectPermissionEvent event,
@NotNull String projectId
) {
return (activeUserSession) -> {
try {
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
var accessibleProjectIds = activeUserSession.getUserContext().getAccessibleProjectIds();
if (accessibleProjectIds.contains(event.getObjectId())) {
return;
}
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
isAccessibleNow = project.findWebConnectionInfo(objectId) != null;
if (isAccessibleNow) {
return;
}
project.addAccessibleConnectionToCache(objectId);
webSession.addSessionEvent(
WSDataSourceEvent.create(
event.getSessionId(),
event.getUserId(),
project.getId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
project.removeAccessibleConnectionFromCache(objectId);
webSession.addSessionEvent(
WSDataSourceEvent.delete(
event.getSessionId(),
event.getUserId(),
project.getId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
}
activeUserSession.addSessionProject(projectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.create(
event.getSessionId(),
event.getUserId(),
projectId
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
activeUserSession.removeSessionProject(projectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.delete(
event.getSessionId(),
event.getUserId(),
projectId
)
);
}
} catch (DBException e) {
log.error("Error on changing permissions for project " +
event.getObjectId() + " in session " + activeUserSession.getSessionId(), e);
}
} catch (DBException e) {
log.error("Error on changing permissions for project " +
event.getObjectId() + " in session " + activeUserSession.getSessionId(), e);
}
};
}

@Override
Expand Down
7 changes: 0 additions & 7 deletions webapp/packages/core-blocks/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,6 @@ export const Button = observer<ButtonProps>(function Button({
['click'],
);

function handleEnter(event: React.KeyboardEvent<HTMLElement>) {
if (event.key === 'Enter') {
event.currentTarget.click();
}
}

loading = state.loading || loading;

if (loading) {
Expand All @@ -89,7 +83,6 @@ export const Button = observer<ButtonProps>(function Button({
<Button
role="button"
tabIndex={0}
onKeyDown={handleEnter}
{...rest}
type={type}
disabled={disabled}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
import { observer } from 'mobx-react-lite';

import { type AdministrationItemContentComponent } from '@cloudbeaver/core-administration';
import { type AdministrationItemContentComponent, ConfigurationWizardService } from '@cloudbeaver/core-administration';
import {
ColoredContainer,
ConfirmationDialog,
Expand Down Expand Up @@ -51,6 +51,7 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser
const commonDialogService = useService(CommonDialogService);
const notificationService = useService(NotificationService);
const serverConfigurationFormStateManager = useService(ServerConfigurationFormStateManager);
const configurationWizardService = useService(ConfigurationWizardService);

const formState = serverConfigurationFormStateManager.formState!;
const part = getServerConfigurationFormPart(formState);
Expand All @@ -71,6 +72,11 @@ export const ServerConfigurationPage: AdministrationItemContentComponent = obser
const changed = part.isChanged;

async function save() {
if (configurationWizard) {
configurationWizardService.next();
return;
}

if (changed) {
const result = await commonDialogService.open(ConfirmationDialog, {
title: 'administration_server_configuration_save_confirmation_title',
Expand Down

0 comments on commit 1688a7e

Please sign in to comment.