Skip to content

Commit

Permalink
Merge branch 'devel' into CB-4127-ssl-tab-show-certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
dariamarutkina authored Oct 31, 2023
2 parents 951e305 + 0f9e7b6 commit 14c8f64
Show file tree
Hide file tree
Showing 45 changed files with 403 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
*/
package io.cloudbeaver.utils;

import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
Expand Down Expand Up @@ -209,4 +212,12 @@ public static String getGlobalProjectId() {
return RMProjectType.GLOBAL.getPrefix() + "_" + globalConfigurationName;
}

public static WebProjectImpl getProjectById(WebSession webSession, String projectId) throws DBWebException {
WebProjectImpl project = webSession.getProjectById(projectId);
if (project == null) {
throw new DBWebException("Project '" + projectId + "' not found");
}
return project;
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
package io.cloudbeaver.service;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBPlatform;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.data.json.JSONUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Map;

public abstract class WebServiceServletBase extends HttpServlet {

private static final Log log = Log.getLog(WebServiceServletBase.class);
private static final Type MAP_STRING_OBJECT_TYPE = JSONUtils.MAP_TYPE_TOKEN;
private static final String REQUEST_PARAM_VARIABLES = "variables";
private static final Gson gson = new GsonBuilder()
.serializeNulls()
.setPrettyPrinting()
.create();

private final CBApplication application;

Expand Down Expand Up @@ -43,4 +54,7 @@ protected final void service(HttpServletRequest request, HttpServletResponse res

protected abstract void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException;

protected Map<String, Object> getVariables(HttpServletRequest request) {
return gson.fromJson(request.getParameter(REQUEST_PARAM_VARIABLES), MAP_STRING_OBJECT_TYPE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,22 @@
package io.cloudbeaver.service.fs;

import io.cloudbeaver.DBWebException;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.service.DBWBindingContext;
import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.service.DBWServletContext;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.fs.impl.WebServiceFS;
import io.cloudbeaver.service.fs.model.WebFSServlet;
import org.jkiss.dbeaver.DBException;
import org.jkiss.utils.CommonUtils;

import java.net.URI;

/**
* Web service implementation
*/
public class WebServiceBindingFS extends WebServiceBindingBase<DBWServiceFS> {
public class WebServiceBindingFS extends WebServiceBindingBase<DBWServiceFS> implements DBWServiceBindingServlet<CBApplication> {

private static final String SCHEMA_FILE_NAME = "schema/service.fs.graphqls";

Expand All @@ -43,41 +48,48 @@ public void bindWiring(DBWBindingContext model) throws DBWebException {
.dataFetcher("fsFile",
env -> getService(env).getFile(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("fileURI")))
URI.create(env.getArgument("fileURI"))
)
)
.dataFetcher("fsListFiles",
env -> getService(env).getFiles(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("folderURI")))
URI.create(env.getArgument("folderURI"))
)
)
.dataFetcher("fsReadFileContentAsString",
env -> getService(env).readFileContent(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("fileURI")))
URI.create(env.getArgument("fileURI"))
)
)
;
model.getMutationType()
.dataFetcher("fsCreateFile",
env -> getService(env).createFile(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("fileURI")))
URI.create(env.getArgument("fileURI"))
)
)
.dataFetcher("fsCreateFolder",
env -> getService(env).createFolder(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("folderURI")))
URI.create(env.getArgument("folderURI"))
)
)
.dataFetcher("fsDeleteFile",
env -> getService(env).deleteFile(getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("fileURI")))
URI.create(env.getArgument("fileURI"))
)
)
.dataFetcher("fsMoveFile",
env -> getService(env).moveFile(
getWebSession(env),
env.getArgument("projectId"),
URI.create(env.getArgument("fromURI")),
URI.create(env.getArgument("toURI")))
URI.create(env.getArgument("toURI"))
)
)
.dataFetcher("fsWriteFileStringContent",
env -> getService(env).writeFileContent(
Expand All @@ -90,4 +102,13 @@ public void bindWiring(DBWBindingContext model) throws DBWebException {
)
;
}

@Override
public void addServlets(CBApplication application, DBWServletContext servletContext) throws DBException {
servletContext.addServlet(
"fileSystems",
new WebFSServlet(application, getServiceImpl()),
application.getServicesURI() + "fs-data/*"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2023 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.service.fs.model;

import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.service.WebServiceServletBase;
import io.cloudbeaver.service.fs.DBWServiceFS;
import org.eclipse.jetty.server.Request;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;

import javax.servlet.MultipartConfigElement;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;

@MultipartConfig()
public class WebFSServlet extends WebServiceServletBase {
private static final String PARAM_PROJECT_ID = "projectId";
private final DBWServiceFS fs;

public WebFSServlet(CBApplication application, DBWServiceFS fs) {
super(application);
this.fs = fs;
}

@Override
protected void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
if (!session.isAuthorizedInSecurityManager()) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Anonymous access restricted.");
return;
}
if (request.getMethod().equals("POST")) {
doPost(session, request, response);
} else {
doGet(session, request, response);
}

}

private void doGet(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
String projectId = request.getParameter(PARAM_PROJECT_ID);
Path path = getPath(session, projectId, request.getParameter("fileURI"));
session.addInfoMessage("Download data ...");
response.setHeader("Content-Type", "application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + path.getFileName() + "\"");
response.setHeader("Content-Length", String.valueOf(Files.size(path)));

try (InputStream is = Files.newInputStream(path)) {
IOUtils.copyStream(is, response.getOutputStream());
}
}

private void doPost(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
// we need to set this attribute to get parts
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, new MultipartConfigElement(""));
Map<String, Object> variables = getVariables(request);
String projectId = JSONUtils.getString(variables, PARAM_PROJECT_ID);
String uri = JSONUtils.getString(variables, "toURI");
Path path = getPath(session, projectId, uri);
try {
for (Part part : request.getParts()) {
String fileName = part.getSubmittedFileName();
if (CommonUtils.isEmpty(fileName)) {
continue;
}
try (InputStream is = part.getInputStream()) {
Files.copy(is, path.resolve(fileName));
}
}
} catch (Exception e) {
throw new DBWebException("File Upload Failed: Unable to Save File to the File System", e);
}
}

@NotNull
private Path getPath(WebSession session, String projectId, String uri) throws DBException {
if (CommonUtils.isEmpty(projectId)) {
throw new DBWebException("Project ID is not found");
}
if (CommonUtils.isEmpty(uri)) {
throw new DBWebException("URI is not found");
}
return session.getFileSystemManager(projectId).getPathFromString(session.getProgressMonitor(), uri);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ CREATE TABLE {table_prefix}CB_USER_SECRETS

SECRET_LABEL VARCHAR(128),
SECRET_DESCRIPTION VARCHAR(1024),
ENCODING_TYPE VARCHAR(32) NOT NULL DEFAULT 'PLAINTEXT',
ENCODING_TYPE VARCHAR(32) DEFAULT 'PLAINTEXT' NOT NULL,
UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

PRIMARY KEY (USER_ID, SECRET_ID),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ CREATE TABLE {table_prefix}CB_USER_SECRETS
SECRET_LABEL VARCHAR(128),
SECRET_DESCRIPTION VARCHAR(1024),

UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

PRIMARY KEY (USER_ID, SECRET_ID),
FOREIGN KEY (USER_ID) REFERENCES {table_prefix}CB_USER (USER_ID) ON DELETE CASCADE
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ALTER TABLE {table_prefix}CB_USER_SECRETS
ADD COLUMN ENCODING_TYPE VARCHAR(32) NOT NULL DEFAULT 'PLAINTEXT';
ADD COLUMN ENCODING_TYPE VARCHAR(32) DEFAULT 'PLAINTEXT' NOT NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS {table_prefix}CB_WORKSPACE(
FOREIGN KEY(INSTANCE_ID) REFERENCES {table_prefix}CB_INSTANCE(INSTANCE_ID)
);

ALTER TABLE {table_prefix}CB_USER_CREDENTIALS ADD UPDATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE {table_prefix}CB_USER_CREDENTIALS ADD UPDATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;

ALTER TABLE {table_prefix}CB_SESSION ALTER COLUMN LAST_ACCESS_REMOTE_ADDRESS VARCHAR(128) NULL;
ALTER TABLE {table_prefix}CB_SESSION ALTER COLUMN LAST_ACCESS_USER_AGENT VARCHAR(255) NULL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CREATE TABLE {table_prefix}CB_AUTH_TOKEN
USER_ID VARCHAR(128),

EXPIRATION_TIME TIMESTAMP NOT NULL,
CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

PRIMARY KEY (TOKEN_ID),
FOREIGN KEY (SESSION_ID) REFERENCES {table_prefix}CB_SESSION (SESSION_ID) ON DELETE CASCADE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ CREATE TABLE {table_prefix}CB_AUTH_ATTEMPT
SESSION_TYPE VARCHAR(64) NOT NULL,
APP_SESSION_STATE TEXT NOT NULL,

CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

PRIMARY KEY (AUTH_ID),
FOREIGN KEY (SESSION_ID) REFERENCES {table_prefix}CB_SESSION (SESSION_ID) ON DELETE CASCADE
Expand All @@ -21,7 +21,7 @@ CREATE TABLE {table_prefix}CB_AUTH_ATTEMPT_INFO
AUTH_PROVIDER_CONFIGURATION_ID VARCHAR(128),
AUTH_STATE TEXT NOT NULL,

CREATE_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,

PRIMARY KEY (AUTH_ID, AUTH_PROVIDER_ID),
FOREIGN KEY (AUTH_ID) REFERENCES {table_prefix}CB_AUTH_ATTEMPT (AUTH_ID) ON DELETE CASCADE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ ALTER TABLE {table_prefix}CB_AUTH_TOKEN
ADD REFRESH_TOKEN_ID VARCHAR(128);

ALTER TABLE {table_prefix}CB_AUTH_TOKEN
ADD REFRESH_TOKEN_EXPIRATION_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ADD REFRESH_TOKEN_EXPIRATION_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,8 @@ public SMUser[] findUsers(@NotNull SMUserFilter filter)
// Read users
try (PreparedStatement dbStat = dbCon.prepareStatement(
database.normalizeTableNames("SELECT USER_ID,IS_ACTIVE,DEFAULT_AUTH_ROLE FROM {table_prefix}CB_USER"
+ buildUsersFilter(filter) + "\nORDER BY USER_ID LIMIT ? OFFSET ?"))) {
+ buildUsersFilter(filter) + "\nORDER BY USER_ID " + getOffsetLimitPart(filter)))) {
int parameterIndex = setUsersFilterValues(dbStat, filter, 1);
dbStat.setInt(parameterIndex++, filter.getPage().getLimit());
dbStat.setInt(parameterIndex++, filter.getPage().getOffset());

try (ResultSet dbResult = dbStat.executeQuery()) {
while (dbResult.next()) {
Expand Down Expand Up @@ -424,6 +422,10 @@ public SMUser[] findUsers(@NotNull SMUserFilter filter)
}
}

private String getOffsetLimitPart(@NotNull SMUserFilter filter) {
return database.getDialect().getOffsetLimitQueryPart(filter.getPage().getOffset(), filter.getPage().getLimit());
}

private String buildUsersFilter(SMUserFilter filter) {
StringBuilder where = new StringBuilder();
List<String> whereParts = new ArrayList<>();
Expand Down Expand Up @@ -2758,9 +2760,10 @@ public void clearOldAuthAttemptInfo() throws DBException {
"WHERE EXISTS " +
"(SELECT 1 FROM {table_prefix}CB_AUTH_ATTEMPT AA " +
"LEFT JOIN {table_prefix}CB_AUTH_TOKEN CAT ON AA.SESSION_ID = CAT.SESSION_ID " +
"WHERE (CAT.REFRESH_TOKEN_EXPIRATION_TIME < NOW() OR CAT.EXPIRATION_TIME IS NULL) " +
"WHERE (CAT.REFRESH_TOKEN_EXPIRATION_TIME < ? OR CAT.EXPIRATION_TIME IS NULL) " +
"AND AA.AUTH_ID=AAI.AUTH_ID AND AUTH_STATUS='" + SMAuthStatus.EXPIRED + "') " +
"AND CREATE_TIME<?"),
Timestamp.valueOf(LocalDateTime.now()),
Timestamp.valueOf(LocalDateTime.now().minusMinutes(smConfig.getExpiredAuthAttemptInfoTtl()))
);
} catch (SQLException e) {
Expand Down
Loading

0 comments on commit 14c8f64

Please sign in to comment.