Skip to content

Commit

Permalink
Merge branch 'devel' into CB-4694-te-admin-can-assign-his-own-team
Browse files Browse the repository at this point in the history
  • Loading branch information
kseniaguzeeva authored Feb 23, 2024
2 parents 34215f4 + 9ba77f1 commit 784206f
Show file tree
Hide file tree
Showing 122 changed files with 1,236 additions and 531 deletions.
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io

## Changelog

### 23.3.5. 2024-02-19
- Default user group was added to the product. This group includes all users. You cannot delete users from this group;
- Added the ability to disable alias autocomplete for all users in the admin panel;
- Different bug fixes and enhancements have been made.

### 23.3.4. 2024-02-05
- Text wrap is activated by default for texts and BLOBs in the Values panel for better visibility. User can switch to the one-line mode using a button on the toolbar;
- Added the ability to edit the default preferences of the following parts: interface, tools and data viewer in the settings panel in the administrative part;
Expand All @@ -42,10 +47,3 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io
- Added the ability to view decoded binary-type data in the Value panel;
- Enhanced security for unauthorized access;
- Different bug fixes and enhancements have been made.



### Old CloudBeaver releases

You can find information about earlier releases on the CloudBeaver wiki https://github.com/dbeaver/cloudbeaver/wiki/Releases.

4 changes: 3 additions & 1 deletion deploy/build-backend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ echo "Pull cloudbeaver platform"
cd ../..

echo "Pull dbeaver platform"
[ ! -d dbeaver ] && git clone https://github.com/dbeaver/dbeaver.git
[ ! -d dbeaver ] && git clone --depth 1 https://github.com/dbeaver/dbeaver.git
[ ! -d dbeaver-common ] && git clone --depth 1 https://github.com/dbeaver/dbeaver-common.git


cd cloudbeaver/deploy

Expand Down
1 change: 1 addition & 0 deletions deploy/build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ cd ..\..
echo Pull dbeaver platform

IF NOT EXIST dbeaver git clone https://github.com/dbeaver/dbeaver.git
IF NOT EXIST dbeaver-common git clone https://github.com/dbeaver/dbeaver-common.git
cd cloudbeaver\deploy

echo Build cloudbeaver server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,5 +448,12 @@ public int getKeepAliveInterval() {
return dataSourceContainer.getConnectionConfiguration().getKeepAliveInterval();
}

@Property
public List<WebSecretInfo> getSharedSecrets() throws DBException {
return dataSourceContainer.listSharedCredentials()
.stream()
.map(WebSecretInfo::new)
.collect(Collectors.toList());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2024 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.cloudbeaver.model;

import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;

public class WebSecretInfo {
private final DBSSecretValue secretValue;

public WebSecretInfo(DBSSecretValue secretValue) {
this.secretValue = secretValue;
}

@Property
public String getDisplayName() {
return secretValue.getDisplayName();
}

@Property
public String getSecretId() {
return secretValue.getUniqueId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
import org.jkiss.dbeaver.model.auth.SMAuthProvider;
import org.jkiss.dbeaver.model.auth.SMSession;
import org.jkiss.dbeaver.model.auth.SMSessionPrincipal;
Expand All @@ -41,7 +42,10 @@ public class WebAuthInfo implements SMSessionPrincipal {
private final WebUser user;
private final WebAuthProviderDescriptor authProvider;
private String authProviderConfigurationId;
private SMSession authSession;
@NotNull
private final SMAuthInfo authInfo;
@NotNull
private final SMSession authSession;
private final OffsetDateTime loginTime;
private final DBWUserIdentity userIdentity;
private String message;
Expand All @@ -54,12 +58,14 @@ public WebAuthInfo(
@NotNull WebAuthProviderDescriptor authProvider,
@NotNull DBWUserIdentity userIdentity,
@NotNull SMSession authSession,
@NotNull SMAuthInfo authInfo,
@NotNull OffsetDateTime loginTime
) {
this.session = session;
this.user = user;
this.authProvider = authProvider;
this.userIdentity = userIdentity;
this.authInfo = authInfo;
this.authSession = authSession;
this.loginTime = loginTime;
}
Expand Down Expand Up @@ -120,10 +126,16 @@ public WebAuthProviderDescriptor getAuthProviderDescriptor() {
return authProvider;
}

@NotNull
public SMSession getAuthSession() {
return authSession;
}

@NotNull
public SMAuthInfo getAuthInfo() {
return authInfo;
}

void closeAuth() {
if (authProvider != null && authSession != null) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
* Is the main source of data in web application
*/
public class WebSession extends BaseWebSession
implements SMSession, SMCredentialsProvider, DBACredentialsProvider, IAdaptable {
implements SMSessionWithAuth, SMCredentialsProvider, DBACredentialsProvider, IAdaptable {

private static final Log log = Log.getLog(WebSession.class);

Expand Down Expand Up @@ -813,6 +813,14 @@ public WebAuthInfo getAuthInfo(@Nullable String providerID) {
}
}

@Override
public List<SMAuthInfo> getAuthInfos() {
synchronized (authTokens) {
return authTokens.stream().map(WebAuthInfo::getAuthInfo).toList();
}
}


public List<WebAuthInfo> getAllAuthInfo() {
synchronized (authTokens) {
return new ArrayList<>(authTokens);
Expand Down Expand Up @@ -1008,6 +1016,17 @@ public WebProjectImpl getProjectById(@Nullable String projectId) {
return getWorkspace().getProjectById(projectId);
}

public WebProjectImpl getAccessibleProjectById(@Nullable String projectId) throws DBWebException {
WebProjectImpl project = null;
if (projectId != null) {
project = getWorkspace().getProjectById(projectId);
}
if (project == null) {
throw new DBWebException("Project not found: " + projectId);
}
return project;
}

public List<WebProjectImpl> getAccessibleProjects() {
return getWorkspace().getProjects();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ private List<WebAuthInfo> finishWebSessionAuthorization(SMAuthInfo authInfo) thr
authProviderDescriptor,
userIdentity,
authSession,
authInfo,
OffsetDateTime.now()
);
webAuthInfo.setAuthProviderConfigurationId(authConfiguration.getAuthProviderConfigurationId());
Expand Down
12 changes: 10 additions & 2 deletions server/bundles/io.cloudbeaver.server/schema/service.core.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@ type NetworkHandlerConfig {
secureProperties: Object!
}

type SecretInfo {
displayName: String!
secretId: String!
}

# Connection instance
type ConnectionInfo {
id: ID!
Expand Down Expand Up @@ -337,6 +342,8 @@ type ConnectionInfo {
saveCredentials: Boolean!
# Shared credentials - the same for all users, stored in secure storage.
sharedCredentials: Boolean!

sharedSecrets: [SecretInfo!]! @since(version: "23.3.5")
# Determines that credentials were saved for current user.
# This field read is slow, it should be read only when it really needed
credentialsSaved: Boolean!
Expand Down Expand Up @@ -488,6 +495,7 @@ input ConnectionConfig {
saveCredentials: Boolean
sharedCredentials: Boolean
authModelId: ID
selectedSecretId: ID @since(version: "23.3.5")
credentials: Object

# Map of provider properties (name/value)
Expand Down Expand Up @@ -584,14 +592,14 @@ extend type Mutation {
copyConnectionFromNode( nodePath: String!, config: ConnectionConfig, projectId: ID ): ConnectionInfo!

# Test connection configuration. Returns remote server version
testConnection( config: ConnectionConfig!, projectId: ID ): ConnectionInfo!
testConnection( config: ConnectionConfig!, projectId: ID): ConnectionInfo!

# Test connection configuration. Returns remote server version
testNetworkHandler( config: NetworkHandlerConfigInput! ): NetworkEndpointInfo!

# Initiate existing connection
initConnection( id: ID!, projectId: ID, credentials: Object, networkCredentials: [NetworkHandlerConfigInput!],
saveCredentials:Boolean, sharedCredentials: Boolean ): ConnectionInfo!
saveCredentials:Boolean, sharedCredentials: Boolean, selectedSecretId:String ): ConnectionInfo!

# Disconnect from database
closeConnection( id: ID!, projectId: ID ): ConnectionInfo!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model;

import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.connection.DBPDriverConfigurationType;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.meta.Property;
Expand Down Expand Up @@ -59,6 +60,7 @@ public class WebConnectionConfig {
private Map<String, Object> providerProperties;
private List<WebNetworkHandlerConfigInput> networkHandlersConfig;
private DBPDriverConfigurationType configurationType;
private String selectedSecretId;

public WebConnectionConfig() {
}
Expand Down Expand Up @@ -91,6 +93,7 @@ public WebConnectionConfig(Map<String, Object> params) {
properties = JSONUtils.getObjectOrNull(params, "properties");
userName = JSONUtils.getString(params, "userName");
userPassword = JSONUtils.getString(params, "userPassword");
selectedSecretId = JSONUtils.getString(params, "selectedSecretId");

authModelId = JSONUtils.getString(params, "authModelId");
credentials = JSONUtils.getObjectOrNull(params, "credentials");
Expand Down Expand Up @@ -231,4 +234,9 @@ public Map<String, Object> getProviderProperties() {
public Integer getKeepAliveInterval() {
return keepAliveInterval;
}

@Nullable
public String getSelectedSecretId() {
return selectedSecretId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ WebConnectionInfo initConnection(
@NotNull Map<String, Object> authProperties,
@Nullable List<WebNetworkHandlerConfigInput> networkCredentials,
@Nullable Boolean saveCredentials,
@Nullable Boolean sharedCredentials
@Nullable Boolean sharedCredentials,
@Nullable String selectedCredentials
) throws DBWebException;

@WebProjectAction(requireProjectPermissions = {RMConstants.PERMISSION_PROJECT_DATASOURCES_EDIT})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ public void bindWiring(DBWBindingContext model) throws DBWebException {
env.getArgument("credentials"),
nhc,
env.getArgument("saveCredentials"),
env.getArgument("sharedCredentials")
env.getArgument("sharedCredentials"),
env.getArgument("selectedSecretId")
);
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.secret.DBSSecretController;
import org.jkiss.dbeaver.model.secret.DBSSecretValue;
import org.jkiss.dbeaver.model.websocket.WSConstants;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
Expand Down Expand Up @@ -318,15 +319,32 @@ public WebConnectionInfo initConnection(
@NotNull Map<String, Object> authProperties,
@Nullable List<WebNetworkHandlerConfigInput> networkCredentials,
@Nullable Boolean saveCredentials,
@Nullable Boolean sharedCredentials
@Nullable Boolean sharedCredentials,
@Nullable String selectedSecretId
) throws DBWebException {
WebConnectionInfo connectionInfo = webSession.getWebConnectionInfo(projectId, connectionId);
connectionInfo.setSavedCredentials(authProperties, networkCredentials);

DBPDataSourceContainer dataSourceContainer = connectionInfo.getDataSourceContainer();
var dataSourceContainer = (DataSourceDescriptor) connectionInfo.getDataSourceContainer();
if (dataSourceContainer.isConnected()) {
throw new DBWebException("Datasource '" + dataSourceContainer.getName() + "' is already connected");
}
if (dataSourceContainer.isSharedCredentials() && selectedSecretId != null) {
List<DBSSecretValue> allSecrets;
try {
allSecrets = dataSourceContainer.listSharedCredentials();
} catch (DBException e) {
throw new DBWebException("Error loading connection secret", e);
}
DBSSecretValue selectedSecret =
allSecrets.stream()
.filter(secret -> selectedSecretId.equals(secret.getUniqueId()))
.findFirst().orElse(null);
if (selectedSecret == null) {
throw new DBWebException("Secret not found:" + selectedSecretId);
}
dataSourceContainer.setSelectedSharedCredentials(selectedSecret);
}

boolean oldSavePassword = dataSourceContainer.isSavePassword();
try {
Expand Down Expand Up @@ -642,12 +660,12 @@ public WebConnectionInfo testConnection(

connectionConfig.setSaveCredentials(true); // It is used in createConnectionFromConfig

DBPDataSourceContainer dataSource = WebDataSourceUtils.getLocalOrGlobalDataSource(
DataSourceDescriptor dataSource = (DataSourceDescriptor) WebDataSourceUtils.getLocalOrGlobalDataSource(
CBApplication.getInstance(), webSession, projectId, connectionId);

WebProjectImpl project = getProjectById(webSession, projectId);
DBPDataSourceRegistry sessionRegistry = project.getDataSourceRegistry();
DBPDataSourceContainer testDataSource;
DataSourceDescriptor testDataSource;
if (dataSource != null) {
try {
// Check that creds are saved to trigger secrets resolve
Expand All @@ -656,12 +674,27 @@ public WebConnectionInfo testConnection(
throw new DBWebException("Can't determine whether datasource credentials are saved", e);
}

testDataSource = dataSource.createCopy(dataSource.getRegistry());
testDataSource = (DataSourceDescriptor) dataSource.createCopy(dataSource.getRegistry());
WebServiceUtils.setConnectionConfiguration(
testDataSource.getDriver(),
testDataSource.getConnectionConfiguration(),
connectionConfig
);
if (connectionConfig.getSelectedSecretId() != null) {
try {
DBSSecretValue secretValue = dataSource.listSharedCredentials()
.stream()
.filter(secret -> connectionConfig.getSelectedSecretId().equals(secret.getSubjectId()))
.findFirst()
.orElse(null);

if (secretValue != null) {
testDataSource.setSelectedSharedCredentials(secretValue);
}
} catch (DBException e) {
throw new DBWebException("Failed to load secret value: " + connectionConfig.getSelectedSecretId());
}
}
WebServiceUtils.saveAuthProperties(
testDataSource,
testDataSource.getConnectionConfiguration(),
Expand All @@ -671,7 +704,8 @@ public WebConnectionInfo testConnection(
true
);
} else {
testDataSource = WebServiceUtils.createConnectionFromConfig(connectionConfig, sessionRegistry);
testDataSource = (DataSourceDescriptor) WebServiceUtils.createConnectionFromConfig(connectionConfig,
sessionRegistry);
}
webSession.provideAuthParameters(webSession.getProgressMonitor(), testDataSource, testDataSource.getConnectionConfiguration());
testDataSource.setSavePassword(true); // We need for test to avoid password callback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ interface RPConstants {
String PARAM_FIRST_NAME = "first-name-header";
String PARAM_LAST_NAME = "last-name-header";
String PARAM_ROLE_NAME = "role-header";
String PARAM_TEAM_DELIMITER = "team-delimiter";
}
Loading

0 comments on commit 784206f

Please sign in to comment.