diff --git a/server/bundles/io.cloudbeaver.connect.provider.sample/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.connect.provider.sample/META-INF/MANIFEST.MF
index 4584ff7e72..bb5b609afd 100644
--- a/server/bundles/io.cloudbeaver.connect.provider.sample/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.connect.provider.sample/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.connect.provider.sample;singleton:=true
-Bundle-Version: 1.0.23.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.24.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.connect.provider.sample/pom.xml b/server/bundles/io.cloudbeaver.connect.provider.sample/pom.xml
index 77cdaff994..ad4d275461 100644
--- a/server/bundles/io.cloudbeaver.connect.provider.sample/pom.xml
+++ b/server/bundles/io.cloudbeaver.connect.provider.sample/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.connect.provider.sample
- 1.0.23-SNAPSHOT
+ 1.0.24-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
index 123687ecf8..805213a842 100644
--- a/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.product.ce/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
-Bundle-Version: 20.0.4.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 20.0.5.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.product.ce/pom.xml b/server/bundles/io.cloudbeaver.product.ce/pom.xml
index afe543248e..7ff2fe0dd4 100644
--- a/server/bundles/io.cloudbeaver.product.ce/pom.xml
+++ b/server/bundles/io.cloudbeaver.product.ce/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.product.ce
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
index afe99dc848..b5d38eb0be 100644
--- a/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.resources.drivers.base/META-INF/MANIFEST.MF
@@ -2,8 +2,8 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Base JDBC drivers
Bundle-SymbolicName: io.cloudbeaver.resources.drivers.base;singleton:=true
-Bundle-Version: 1.0.20.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.21.qualifier
+Bundle-Release-Date: 20210322
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
diff --git a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
index c1e1a6413a..5ce61b1cc1 100644
--- a/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
+++ b/server/bundles/io.cloudbeaver.resources.drivers.base/pom.xml
@@ -9,6 +9,6 @@
../
io.cloudbeaver.resources.drivers.base
- 1.0.20-SNAPSHOT
+ 1.0.21-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
index 961229c43f..2876e771fb 100644
--- a/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.server/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
-Bundle-Version: 20.0.4.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 20.0.5.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.WebPlatformActivator
diff --git a/server/bundles/io.cloudbeaver.server/pom.xml b/server/bundles/io.cloudbeaver.server/pom.xml
index 59511cfd2e..1c2775b202 100644
--- a/server/bundles/io.cloudbeaver.server/pom.xml
+++ b/server/bundles/io.cloudbeaver.server/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.server
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/DBWAuthProviderExternal.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/DBWAuthProviderExternal.java
index a343e7a2af..f781b2e3b0 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/DBWAuthProviderExternal.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/DBWAuthProviderExternal.java
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver;
+import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.model.user.WebUser;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
@@ -49,7 +50,8 @@ public interface DBWAuthProviderExternal extend
@NotNull DBRProgressMonitor monitor,
@NotNull DBWSecurityController securityController,
@NotNull Map providerConfig,
- @NotNull Map credentials) throws DBException;
+ @NotNull Map credentials,
+ @Nullable WebUser activeUser) throws DBException;
@Nullable
String getUserDisplayName(
@@ -60,7 +62,8 @@ public interface DBWAuthProviderExternal extend
@Nullable
DBPObject getUserDetails(
@NotNull DBRProgressMonitor monitor,
- AUTH_SESSION session,
+ @NotNull WebSession webSession,
+ @NotNull AUTH_SESSION session,
@NotNull WebUser user) throws DBException;
}
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java
index b61f7267f2..56f74fab8e 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/session/WebSession.java
@@ -97,7 +97,8 @@ public class WebSession implements DBASession, DBAAuthCredentialsProvider, IAdap
private final Map asyncTasks = new HashMap<>();
private final Map attributes = new HashMap<>();
private final Map> attributeDisposers = new HashMap<>();
- private WebAuthInfo authInfo;
+ // Map of auth tokens. Key is authentication provdier
+ private final List authTokens = new ArrayList<>();
private DBNModel navigatorModel;
private DBRProgressMonitor progressMonitor = new SessionProgressMonitor();
@@ -477,10 +478,7 @@ public class WebSession implements DBASession, DBAAuthCredentialsProvider, IAdap
} catch (Throwable e) {
log.error(e);
}
- if (this.authInfo != null) {
- this.authInfo.closeAuth();
- this.authInfo = null;
- }
+ clearAuthTokens();
this.user = null;
if (this.sessionProject != null) {
@@ -489,6 +487,16 @@ public class WebSession implements DBASession, DBAAuthCredentialsProvider, IAdap
}
}
+ private void clearAuthTokens() {
+ ArrayList tokensCopy;
+ synchronized (authTokens) {
+ tokensCopy = new ArrayList<>(this.authTokens);
+ }
+ for (WebAuthInfo ai : tokensCopy) {
+ removeAuthInfo(ai);
+ }
+ }
+
public DBRProgressMonitor getProgressMonitor() {
return progressMonitor;
}
@@ -622,30 +630,69 @@ public class WebSession implements DBASession, DBAAuthCredentialsProvider, IAdap
}
}
- public WebAuthInfo getAuthInfo() {
- return authInfo;
+ public WebAuthInfo getAuthInfo(@Nullable String providerID) {
+ synchronized (authTokens) {
+
+ if (providerID != null) {
+ for (WebAuthInfo ai : authTokens) {
+ if (ai.getAuthProvider().getId().equals(providerID)) {
+ return ai;
+ }
+ }
+ return null;
+ }
+ return authTokens.isEmpty() ? null : authTokens.get(0);
+ }
}
- public void setAuthInfo(@Nullable WebAuthInfo authInfo) {
- WebUser newUser = authInfo == null ? null : authInfo.getUser();
- if (CommonUtils.equalObjects(this.user, newUser)) {
- return;
+ public List getAllAuthInfo() {
+ synchronized (authTokens) {
+ return new ArrayList<>(authTokens);
}
- forceUserRefresh(newUser);
+ }
- if (this.authInfo != null) {
- DBASession oldAuthSession = this.authInfo.getAuthSession();
- if (oldAuthSession != null) {
- sessionProject.getSessionContext().removeSession(oldAuthSession);
- }
- this.authInfo.closeAuth();
+ public void addAuthInfo(@NotNull WebAuthInfo authInfo) throws DBException {
+ WebUser newUser = authInfo.getUser();
+ if (this.user == null && newUser != null) {
+ forceUserRefresh(newUser);
+ } else if (!CommonUtils.equalObjects(this.user, newUser)) {
+ throw new DBException("Can't authorize different users in the single session");
}
- this.authInfo = authInfo;
- if (authInfo != null) {
- DBASession authSession = authInfo.getAuthSession();
- if (authSession != null) {
- this.sessionProject.getSessionContext().addSession(authSession);
- }
+
+
+ WebAuthInfo oldAuthInfo = getAuthInfo(authInfo.getAuthProvider().getId());
+ if (oldAuthInfo != null) {
+ removeAuthInfo(oldAuthInfo);
+ }
+
+ synchronized (authTokens) {
+ authTokens.add(authInfo);
+ }
+ DBASession authSession = authInfo.getAuthSession();
+ if (authSession != null) {
+ this.sessionProject.getSessionContext().addSession(authSession);
+ }
+ }
+
+ private void removeAuthInfo(WebAuthInfo oldAuthInfo) {
+ DBASession oldAuthSession = oldAuthInfo.getAuthSession();
+ if (oldAuthSession != null && sessionProject != null) {
+ sessionProject.getSessionContext().removeSession(oldAuthSession);
+ }
+ oldAuthInfo.closeAuth();
+ synchronized (authTokens) {
+ authTokens.remove(oldAuthInfo);
+ }
+ }
+
+ public void removeAuthInfo(String providerId) {
+ if (providerId == null) {
+ clearAuthTokens();
+ } else {
+ removeAuthInfo(getAuthInfo(providerId));
+ }
+ if (authTokens.isEmpty()) {
+ forceUserRefresh(null);
}
}
@@ -705,9 +752,13 @@ public class WebSession implements DBASession, DBAAuthCredentialsProvider, IAdap
// May be called to extract auth information from session
@Override
public T getAdapter(Class adapter) {
- if (authInfo != null && authInfo.getAuthSession() != null) {
- if (adapter.isInstance(authInfo.getAuthSession())) {
- return adapter.cast(authInfo.getAuthSession());
+ synchronized (authTokens) {
+ for (WebAuthInfo authInfo : authTokens) {
+ if (authInfo != null && authInfo.getAuthSession() != null) {
+ if (adapter.isInstance(authInfo.getAuthSession())) {
+ return adapter.cast(authInfo.getAuthSession());
+ }
+ }
}
}
return null;
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebUserOriginInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebUserOriginInfo.java
index caf9aeeade..b291dcab21 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebUserOriginInfo.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/model/user/WebUserOriginInfo.java
@@ -23,10 +23,12 @@ import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.auth.provider.local.LocalAuthProvider;
import io.cloudbeaver.model.WebObjectOrigin;
import io.cloudbeaver.model.WebPropertyInfo;
+import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
+import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPObject;
import org.jkiss.dbeaver.model.access.DBASession;
@@ -91,13 +93,18 @@ public class WebUserOriginInfo implements WebObjectOrigin {
return new WebPropertyInfo[0];
}
try {
- DBASession authSession = session.getAuthInfo().getAuthSession();
+ WebAuthInfo authInfo = session.getAuthInfo(
+ LocalAuthProvider.PROVIDER_ID.equals(authProvider.getId()) ? null : authProvider.getId());
+ if (authInfo == null) {
+ throw new DBException("Session not authorized in auth provider '" + authProvider.getId() + "'");
+ }
+ DBASession authSession = authInfo.getAuthSession();
DBWAuthProvider> authProvider = this.authProvider.getInstance();
if (authSession != null && authProvider instanceof DBWAuthProviderExternal) {
if (!isValidSessionType(authSession, authProvider)) {
return new WebPropertyInfo[0];
}
- DBPObject userDetails = ((DBWAuthProviderExternal) authProvider).getUserDetails(session.getProgressMonitor(), authSession, user);
+ DBPObject userDetails = ((DBWAuthProviderExternal) authProvider).getUserDetails(session.getProgressMonitor(), session, authSession, user);
if (userDetails != null) {
return WebServiceUtils.getObjectProperties(session, userDetails);
}
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
index 8e910da128..2deca20080 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/CBApplication.java
@@ -224,7 +224,7 @@ public class CBApplication extends BaseApplicationImpl {
log.debug("\tContent root: " + new File(contentRoot).getAbsolutePath());
log.debug("\tDrivers storage: " + new File(driversLocation).getAbsolutePath());
//log.debug("\tDrivers root: " + driversLocation);
- log.debug("\tProduct details: " + application.getInfoDetails());
+ //log.debug("\tProduct details: " + application.getInfoDetails());
log.debug("\tBase port: " + serverPort);
log.debug("\tBase URI: " + servicesURI);
if (develMode) {
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java
index e666cce5a9..547a746ab1 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceBindingBase.java
@@ -25,6 +25,7 @@ import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.server.graphql.GraphQLEndpoint;
+import org.jkiss.code.NotNull;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
@@ -107,8 +108,14 @@ public abstract class WebServiceBindingBase impleme
getServletRequest(env));
}
+ @NotNull
protected static WebConnectionInfo getWebConnection(DataFetchingEnvironment env) throws DBWebException {
- return getWebSession(env).getWebConnectionInfo(env.getArgument("connectionId"));
+ return getWebConnection(getWebSession(env), env.getArgument("connectionId"));
+ }
+
+ @NotNull
+ public static WebConnectionInfo getWebConnection(WebSession session, String connectionId) throws DBWebException {
+ return session.getWebConnectionInfo(connectionId);
}
private class ServiceInvocationHandler implements InvocationHandler {
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java
new file mode 100644
index 0000000000..58f68f9f4a
--- /dev/null
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/WebServiceServletBase.java
@@ -0,0 +1,46 @@
+package io.cloudbeaver.service;
+
+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 javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public abstract class WebServiceServletBase extends HttpServlet {
+
+ private static final Log log = Log.getLog(WebServiceServletBase.class);
+
+ private final CBApplication application;
+
+ public WebServiceServletBase(CBApplication application) {
+ this.application = application;
+ }
+
+ public CBApplication getApplication() {
+ return application;
+ }
+
+ @Override
+ protected final void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ WebSession webSession = CBPlatform.getInstance().getSessionManager().findWebSession(request);
+ if (webSession == null) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Web session not found");
+ return;
+ }
+ try {
+ processServiceRequest(webSession, request, response);
+ } catch (Exception e) {
+ log.error(e);
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Error processing request: " + e.getMessage());
+ }
+ }
+
+ protected abstract void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException;
+
+}
\ No newline at end of file
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java
new file mode 100644
index 0000000000..8c8bbbddb9
--- /dev/null
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLResultServlet.java
@@ -0,0 +1,72 @@
+package io.cloudbeaver.service.sql;
+
+import io.cloudbeaver.DBWebException;
+import io.cloudbeaver.model.session.WebSession;
+import io.cloudbeaver.server.CBApplication;
+import io.cloudbeaver.service.WebServiceServletBase;
+import org.jkiss.dbeaver.DBException;
+import org.jkiss.dbeaver.Log;
+import org.jkiss.utils.CommonUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class WebSQLResultServlet extends WebServiceServletBase {
+
+ private static final Log log = Log.getLog(WebSQLResultServlet.class);
+
+ // context-id/result-id/row-number/attribute-name
+ private static final Pattern URL_PATTERN = Pattern.compile("/?([\\w]+)/([0-9]+)/([0-9]+)/([0-9]+)/(.+)[/\\?]?");
+
+ private final DBWServiceSQL sqlService;
+
+ public WebSQLResultServlet(CBApplication application, DBWServiceSQL sqlService) {
+ super(application);
+ this.sqlService = sqlService;
+ }
+
+ @Override
+ protected void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
+
+ String valuePath = request.getPathInfo();
+ if (CommonUtils.isEmpty(valuePath)) {
+ throw new DBWebException("Result value ID not specified");
+ }
+ Matcher urlMatcher = URL_PATTERN.matcher(valuePath);
+ if (!urlMatcher.matches()) {
+ throw new DBWebException("Invalid URI format");
+ }
+
+ String connectionId = urlMatcher.group(1);
+ String contextId = urlMatcher.group(2);
+ String resultsId = urlMatcher.group(3);
+ String rowNum = urlMatcher.group(4);
+ String attrName = urlMatcher.group(5);
+
+ WebSQLProcessor sqlProcessor = WebServiceBindingSQL.getSQLProcessor(
+ WebServiceBindingSQL.getWebConnection(session, connectionId));
+ WebSQLContextInfo sqlContext = WebServiceBindingSQL.getSQLContext(sqlProcessor, contextId);
+ WebSQLResultsInfo sqlResults = sqlContext.getResults(resultsId);
+
+
+ throw new DBWebException("Not implemented yet");
+/*
+ response.setHeader("Content-Type", processor.getContentType());
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
+ response.setHeader("Content-Length", String.valueOf(dataFile.length()));
+
+ try (InputStream is = new FileInputStream(dataFile)) {
+ IOUtils.copyStream(is, response.getOutputStream());
+ }
+
+ // TODO: cleanup export files ASAP?
+ if (false) {
+ dtConfig.removeTask(taskInfo);
+ }
+*/
+ }
+
+}
\ No newline at end of file
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLUtils.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLUtils.java
index 9ed47f73be..e78e2e7d23 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLUtils.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebSQLUtils.java
@@ -18,6 +18,7 @@ package io.cloudbeaver.service.sql;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBConstants;
+import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.data.*;
import org.jkiss.dbeaver.model.exec.DBCException;
@@ -25,14 +26,12 @@ import org.jkiss.dbeaver.model.gis.DBGeometry;
import org.jkiss.dbeaver.model.struct.DBSAttributeBase;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.dbeaver.utils.ContentUtils;
+import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
/**
* Web SQL utils.
@@ -41,6 +40,8 @@ public class WebSQLUtils {
private static final Log log = Log.getLog(WebSQLUtils.class);
+ public static final int BINARY_PREVIEW_LENGTH = 255;
+
public static Object makeWebCellValue(WebSession session, DBSTypedObject type, Object cellValue, WebDataFormat dataFormat) throws DBCException {
if (cellValue instanceof Date) {
return CBConstants.ISO_DATE_FORMAT.format(cellValue);
@@ -51,11 +52,7 @@ public class WebSQLUtils {
return null;
}
else if (dbValue instanceof DBDDocument) {
- if (dataFormat != WebDataFormat.document) {
- return serializeDocumentValue((DBDDocument) dbValue);
- } else {
- return serializeDocumentValue(session, (DBDDocument) dbValue);
- }
+ return serializeDocumentValue(session, (DBDDocument) dbValue);
} else if (dbValue instanceof DBDComplexValue) {
return serializeComplexValue(session, (DBDComplexValue)dbValue, dataFormat);
} else if (dbValue instanceof DBGeometry) {
@@ -75,18 +72,31 @@ public class WebSQLUtils {
for (int i = 0; i < size; i++) {
items[i] = makeWebCellValue(session, collection.getComponentType(), collection.getItem(i), dataFormat);
}
- return items;
+
+ Map map = createMapOfType("collection");
+ map.put("value", items);
+ return map;
} else if (value instanceof DBDComposite) {
DBDComposite composite = (DBDComposite)value;
- Map map = new LinkedHashMap<>();
+ Map struct = new LinkedHashMap<>();
for (DBSAttributeBase attr : composite.getAttributes()) {
- map.put(attr.getName(), makeWebCellValue(session, attr, composite.getAttributeValue(attr), dataFormat));
+ struct.put(attr.getName(), makeWebCellValue(session, attr, composite.getAttributeValue(attr), dataFormat));
}
+
+ Map map = createMapOfType("map");
+ map.put("value", struct);
return map;
}
return value.toString();
}
+ @NotNull
+ private static Map createMapOfType(String type) {
+ Map map = new LinkedHashMap<>();
+ map.put("$type", type);
+ return map;
+ }
+
private static Map serializeDocumentValue(WebSession session, DBDDocument document) throws DBCException {
String documentData;
try {
@@ -97,7 +107,7 @@ public class WebSQLUtils {
throw new DBCException("Error serializing document", e);
}
- Map map = new LinkedHashMap<>();
+ Map map = createMapOfType("document");
map.put("id", CommonUtils.toString(document.getDocumentId()));
map.put("contentType", document.getDocumentContentType());
map.put("properties", Collections.emptyMap());
@@ -106,15 +116,34 @@ public class WebSQLUtils {
}
private static Object serializeContentValue(WebSession session, DBDContent value) throws DBCException {
- return ContentUtils.getContentStringValue(session.getProgressMonitor(), value);
- }
- private static Object serializeDocumentValue(DBDDocument value) {
- return value;
+ Map map = createMapOfType("content");
+ if (ContentUtils.isTextContent(value)) {
+ String stringValue = ContentUtils.getContentStringValue(session.getProgressMonitor(), value);
+ map.put("text", stringValue);
+ } else {
+ map.put("binary", true);
+ byte[] binaryValue = ContentUtils.getContentBinaryValue(session.getProgressMonitor(), value);
+ if (binaryValue != null) {
+ if (binaryValue.length > BINARY_PREVIEW_LENGTH) {
+ binaryValue = Arrays.copyOf(binaryValue, BINARY_PREVIEW_LENGTH);
+ }
+ map.put("text", GeneralUtils.convertToString(binaryValue, 0, binaryValue.length));
+ } else {
+ map.put("text", null);
+ }
+ }
+ map.put("contentType", value.getContentType());
+ map.put("contentLength", value.getContentLength());
+ return map;
}
private static Object serializeGeometryValue(DBGeometry value) {
- return value.toString();
+ Map map = createMapOfType("geometry");
+ map.put("srid", value.getSRID());
+ map.put("text", value.toString());
+ map.put("properties", value.getProperties());
+ return map;
}
}
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java
index 87d4b7d2d6..652205c81b 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/sql/WebServiceBindingSQL.java
@@ -20,9 +20,14 @@ import graphql.schema.DataFetchingEnvironment;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.session.WebSession;
+import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.service.DBWBindingContext;
+import io.cloudbeaver.service.DBWServiceBindingServlet;
import io.cloudbeaver.service.WebServiceBindingBase;
import io.cloudbeaver.service.sql.impl.WebServiceSQL;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.utils.CommonUtils;
@@ -34,7 +39,7 @@ import java.util.stream.Collectors;
/**
* Web service implementation
*/
-public class WebServiceBindingSQL extends WebServiceBindingBase {
+public class WebServiceBindingSQL extends WebServiceBindingBase implements DBWServiceBindingServlet {
public WebServiceBindingSQL() {
super(DBWServiceSQL.class, new WebServiceSQL(), "schema/service.sql.graphqls");
@@ -109,23 +114,37 @@ public class WebServiceBindingSQL extends WebServiceBindingBase {
));
}
+ @NotNull
private WebDataFormat getDataFormat(DataFetchingEnvironment env) {
String dataFormat = env.getArgument("dataFormat");
return CommonUtils.valueOf(WebDataFormat.class, dataFormat, WebDataFormat.resultset);
}
+ @NotNull
public static WebSQLConfiguration getSQLConfiguration(WebSession webSession) {
return webSession.getAttribute("sqlConfiguration", cfg -> new WebSQLConfiguration(), WebSQLConfiguration::dispose);
}
+ @NotNull
public static WebSQLProcessor getSQLProcessor(DataFetchingEnvironment env) throws DBWebException {
WebConnectionInfo connectionInfo = getWebConnection(env);
+ return getSQLProcessor(connectionInfo);
+ }
+
+ @NotNull
+ public static WebSQLProcessor getSQLProcessor(WebConnectionInfo connectionInfo) throws DBWebException {
return getSQLConfiguration(connectionInfo.getSession()).getSQLProcessor(connectionInfo);
}
+ @NotNull
public static WebSQLContextInfo getSQLContext(DataFetchingEnvironment env) throws DBWebException {
WebSQLProcessor processor = getSQLProcessor(env);
String contextId = env.getArgument("contextId");
+ return getSQLContext(processor, contextId);
+ }
+
+ @NotNull
+ public static WebSQLContextInfo getSQLContext(WebSQLProcessor processor, String contextId) throws DBWebException {
WebSQLContextInfo context = processor.getContext(contextId);
if (context == null) {
throw new DBWebException("SQL context '" + contextId + "' not found");
@@ -133,6 +152,13 @@ public class WebServiceBindingSQL extends WebServiceBindingBase {
return context;
}
+ @Override
+ public void addServlets(CBApplication application, ServletContextHandler servletContextHandler) {
+ servletContextHandler.addServlet(
+ new ServletHolder("sqlResultValueViewer", new WebSQLResultServlet(application, getServiceImpl())),
+ application.getServicesURI() + "sql-result-value/*");
+ }
+
private static class WebSQLConfiguration {
private final Map processors = new HashMap<>();
diff --git a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
index 3509b87bec..2e032529fd 100644
--- a/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.admin/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.service.admin;singleton:=true
-Bundle-Version: 1.0.19.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.20.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.admin/pom.xml b/server/bundles/io.cloudbeaver.service.admin/pom.xml
index 78521e4429..0b698c3de0 100644
--- a/server/bundles/io.cloudbeaver.service.admin/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.admin/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.admin
- 1.0.19-SNAPSHOT
+ 1.0.20-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebAdminLogsServlet.java b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebAdminLogsServlet.java
index e2bc27b89c..afc10e854d 100644
--- a/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebAdminLogsServlet.java
+++ b/server/bundles/io.cloudbeaver.service.admin/src/io/cloudbeaver/service/admin/impl/WebAdminLogsServlet.java
@@ -4,15 +4,14 @@ import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.CBApplication;
-import io.cloudbeaver.server.CBPlatform;
+import io.cloudbeaver.service.WebServiceServletBase;
+import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.MimeTypes;
import org.jkiss.utils.IOUtils;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
@@ -20,55 +19,43 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-public class WebAdminLogsServlet extends HttpServlet {
+public class WebAdminLogsServlet extends WebServiceServletBase {
private static final Log log = Log.getLog(WebAdminLogsServlet.class);
- private final CBApplication application;
-
public WebAdminLogsServlet(CBApplication application) {
- this.application = application;
+ super(application);
}
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- try {
- WebSession webSession = CBPlatform.getInstance().getSessionManager().findWebSession(request);
- if (webSession == null) {
- throw new DBWebException("No active session");
- }
- if (!webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)) {
- response.sendError(HttpServletResponse.SC_FORBIDDEN, "Logs accessible for admins only");
- return;
- }
-
- String logId = request.getPathInfo();
- String logFileName = ".log";
- if ("debug".equals(logId)) {
- logFileName = DBConstants.DEBUG_LOG_FILE_NAME;
- }
- if (logFileName.contains("/") || logFileName.contains("\\")) {
- throw new DBWebException("Bad log file name");
- }
- File logFile = new File(GeneralUtils.getMetadataFolder(), logFileName);
- if (!logFile.exists()) {
- throw new DBWebException("Log file '" + logFileName + "' not found");
- }
-
- response.setHeader("Content-Type", MimeTypes.TEXT_PLAIN);
- if (logFileName.equals(".log")) {
- logFileName = "server.log";
- }
- response.setHeader("Content-Disposition", "attachment; filename=\"" + logFileName + "\"");
-
- try (InputStream is = new FileInputStream(logFile)) {
- IOUtils.copyStream(is, response.getOutputStream());
- }
- } catch (Exception e) {
- log.error(e);
- response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Error reading log: " + e.getMessage());
+ protected void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
+ if (!session.hasPermission(DBWConstants.PERMISSION_ADMIN)) {
+ response.sendError(HttpServletResponse.SC_FORBIDDEN, "Logs accessible for admins only");
return;
}
+
+ String logId = request.getPathInfo();
+ String logFileName = ".log";
+ if ("debug".equals(logId)) {
+ logFileName = DBConstants.DEBUG_LOG_FILE_NAME;
+ }
+ if (logFileName.contains("/") || logFileName.contains("\\")) {
+ throw new DBWebException("Bad log file name");
+ }
+ File logFile = new File(GeneralUtils.getMetadataFolder(), logFileName);
+ if (!logFile.exists()) {
+ throw new DBWebException("Log file '" + logFileName + "' not found");
+ }
+
+ response.setHeader("Content-Type", MimeTypes.TEXT_PLAIN);
+ if (logFileName.equals(".log")) {
+ logFileName = "server.log";
+ }
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + logFileName + "\"");
+
+ try (InputStream is = new FileInputStream(logFile)) {
+ IOUtils.copyStream(is, response.getOutputStream());
+ }
}
}
\ No newline at end of file
diff --git a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
index ba24feafdb..82ca4ac4cd 100644
--- a/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.auth/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.service.auth;singleton:=true
-Bundle-Version: 1.0.19.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.20.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.auth/pom.xml b/server/bundles/io.cloudbeaver.service.auth/pom.xml
index 899c247313..82e2c67f69 100644
--- a/server/bundles/io.cloudbeaver.service.auth/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.auth/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.auth
- 1.0.19-SNAPSHOT
+ 1.0.20-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls b/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls
index e40e3f0a50..817468382b 100644
--- a/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls
+++ b/server/bundles/io.cloudbeaver.service.auth/schema/service.auth.graphqls
@@ -30,29 +30,56 @@ type AuthProviderInfo {
credentialParameters: [AuthCredentialInfo!]!
}
-type UserAuthInfo {
- # User unique identifier
- userId: String!
- # Human readable display name. May be null
- displayName: String
- # Auth provider ID
- authProvider: String!
+type UserAuthToken {
+ # Auth provider used for autgorization
+ provider: ID!
+ # Authorization time
loginTime: DateTime!
# Optional login message
message: String
+ # Auth origin
origin: ObjectOrigin!
}
+type UserAuthInfo {
+ # User unique identifier
+ userId: String! @deprecated
+ # Human readable display name. May be null
+ displayName: String @deprecated
+ # Auth provider ID
+ authProvider: String! @deprecated
+
+ loginTime: DateTime! @deprecated
+
+ # Optional login message
+ message: String @deprecated
+
+ origin: ObjectOrigin! @deprecated
+}
+
+type UserInfo {
+ # User unique identifier
+ userId: String!
+ # Human readable display name. May be null
+ displayName: String
+
+ authTokens: [UserAuthToken!]!
+}
+
extend type Query {
+ # Authorize user using specified auth provider
+
authLogin(provider: ID!, credentials: Object!): UserAuthInfo!
+ # Logouts user. If provider not specified then all authorizations are revoked from session.
+ authLogout(provider: ID): Boolean
- authLogout: Boolean
+ activeUser: UserInfo
- sessionUser: UserAuthInfo
+ sessionUser: UserAuthInfo @deprecated
authProviders: [AuthProviderInfo!]!
diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java
index 52d42e04a0..e6cea14af4 100644
--- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java
+++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/DBWServiceAuth.java
@@ -22,6 +22,8 @@ import io.cloudbeaver.WebAction;
import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.model.user.WebAuthProviderInfo;
+import org.jkiss.code.NotNull;
+import org.jkiss.code.Nullable;
import java.util.Map;
@@ -31,14 +33,18 @@ import java.util.Map;
public interface DBWServiceAuth extends DBWService {
@WebAction(requirePermissions = {} )
- WebAuthInfo authLogin(WebSession webSession, String providerId, Map credentials) throws DBWebException;
+ WebAuthInfo authLogin(@NotNull WebSession webSession, @NotNull String providerId, @NotNull Map credentials) throws DBWebException;
@WebAction(requirePermissions = {} )
- void authLogout(WebSession webSession) throws DBWebException;
+ void authLogout(@NotNull WebSession webSession, @Nullable String providerId) throws DBWebException;
@WebAction(requirePermissions = {})
- WebAuthInfo sessionUser(WebSession webSession) throws DBWebException;
+ WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException;
+
+ @Deprecated
+ @WebAction(requirePermissions = {})
+ WebAuthInfo sessionUser(@NotNull WebSession webSession) throws DBWebException;
@WebAction(requirePermissions = {})
- WebAuthProviderInfo[] getAuthProviders(WebSession webSession);
+ WebAuthProviderInfo[] getAuthProviders(@NotNull WebSession webSession);
}
diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java
index 7e412882b7..87a3ba7e9b 100644
--- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java
+++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebServiceBindingAuth.java
@@ -40,9 +40,10 @@ public class WebServiceBindingAuth extends WebServiceBindingBase
env.getArgument("provider"),
env.getArgument("credentials")))
.dataFetcher("authLogout", env -> {
- getService(env).authLogout(getWebSession(env));
+ getService(env).authLogout(getWebSession(env), env.getArgument("provider"));
return true;
})
+ .dataFetcher("activeUser", env -> getService(env).activeUser(getWebSession(env, false)))
.dataFetcher("sessionUser", env -> getService(env).sessionUser(getWebSession(env, false)))
.dataFetcher("authProviders", env -> getService(env).getAuthProviders(getWebSession(env)))
;
diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java
new file mode 100644
index 0000000000..53aec5fc71
--- /dev/null
+++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/WebUserInfo.java
@@ -0,0 +1,53 @@
+/*
+ * DBeaver - Universal Database Manager
+ * Copyright (C) 2010-2021 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.auth;
+
+import io.cloudbeaver.model.session.WebAuthInfo;
+import io.cloudbeaver.model.session.WebSession;
+import io.cloudbeaver.model.user.WebUser;
+import org.jkiss.dbeaver.Log;
+
+import java.util.List;
+
+/**
+ * WebUserInfo
+ */
+public class WebUserInfo {
+
+ private static final Log log = Log.getLog(WebUserInfo.class);
+
+ private final WebSession session;
+ private final WebUser user;
+
+ public WebUserInfo(WebSession session, WebUser user) {
+ this.session = session;
+ this.user = user;
+ }
+
+ public String getUserId() {
+ return user.getUserId();
+ }
+
+ public String getDisplayName() {
+ return user.getDisplayName();
+ }
+
+ public List getAuthTokens() {
+ return session.getAllAuthInfo();
+ }
+
+}
diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java
index 4d0b51d82b..18e315e983 100644
--- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java
+++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/impl/WebServiceAuthImpl.java
@@ -26,7 +26,11 @@ import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.service.auth.DBWServiceAuth;
+import io.cloudbeaver.service.auth.WebUserInfo;
+import org.jkiss.code.NotNull;
+import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
+import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.access.DBASession;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.utils.CommonUtils;
@@ -40,8 +44,10 @@ import java.util.Map;
*/
public class WebServiceAuthImpl implements DBWServiceAuth {
+ private static final Log log = Log.getLog(WebServiceAuthImpl.class);
+
@Override
- public WebAuthInfo authLogin(WebSession webSession, String providerId, Map authParameters) throws DBWebException {
+ public WebAuthInfo authLogin(@NotNull WebSession webSession, @NotNull String providerId, @NotNull Map authParameters) throws DBWebException {
DBWSecurityController serverController = CBPlatform.getInstance().getApplication().getSecurityController();
if (CommonUtils.isEmpty(providerId)) {
@@ -61,12 +67,12 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
authParameters = authProviderExternal.readExternalCredentials(webSession.getProgressMonitor(), providerConfig, authParameters);
}
- WebUser user = null;
+ WebUser user = webSession.getUser();
String userId = serverController.getUserByCredentials(authProvider, authParameters);
if (userId == null) {
// User doesn't exist. We can create new user automatically if auth provider supports this
if (authProviderExternal != null) {
- user = authProviderExternal.registerNewUser(webSession.getProgressMonitor(), serverController, providerConfig, authParameters);
+ user = authProviderExternal.registerNewUser(webSession.getProgressMonitor(), serverController, providerConfig, authParameters, user);
userId = user.getUserId();
}
@@ -74,6 +80,10 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
throw new DBCException("Invalid user credentials");
}
}
+ if (user != null && !user.getUserId().equals(userId)) {
+ log.debug("Attempt to authorize user '" + userId + "' while user '" + user.getUserId() + "' already authorized");
+ throw new DBCException("You cannot authorize with different users credentials");
+ }
// Check for auth enabled. Auth is always enabled for admins
if (!CBApplication.getInstance().getAppConfiguration().isAuthenticationEnabled()) {
@@ -102,7 +112,7 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
authInfo.setAuthProvider(authProvider);
authInfo.setAuthSession(authSession);
authInfo.setMessage("Authenticated with " + authProvider.getLabel() + " provider");
- webSession.setAuthInfo(authInfo);
+ webSession.addAuthInfo(authInfo);
return authInfo;
} catch (DBException e) {
@@ -111,23 +121,31 @@ public class WebServiceAuthImpl implements DBWServiceAuth {
}
@Override
- public void authLogout(WebSession webSession) throws DBWebException {
+ public void authLogout(@NotNull WebSession webSession, @Nullable String providerId) throws DBWebException {
if (webSession.getUser() == null) {
throw new DBWebException("Not logged in");
}
- webSession.setAuthInfo(null);
+ webSession.removeAuthInfo(providerId);
}
@Override
- public WebAuthInfo sessionUser(WebSession webSession) throws DBWebException {
+ public WebUserInfo activeUser(@NotNull WebSession webSession) throws DBWebException {
if (webSession.getUser() == null) {
return null;
}
- return webSession.getAuthInfo();
+ return new WebUserInfo(webSession, webSession.getUser());
}
@Override
- public WebAuthProviderInfo[] getAuthProviders(WebSession webSession) {
+ public WebAuthInfo sessionUser(@NotNull WebSession webSession) throws DBWebException {
+ if (webSession.getUser() == null) {
+ return null;
+ }
+ return webSession.getAuthInfo(null);
+ }
+
+ @Override
+ public WebAuthProviderInfo[] getAuthProviders(@NotNull WebSession webSession) {
return WebServiceRegistry.getInstance().getAuthProviders()
.stream().map(WebAuthProviderInfo::new)
.toArray(WebAuthProviderInfo[]::new);
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
index f412b5cc2d..2241e38607 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.service.data.transfer;singleton:=true
-Bundle-Version: 1.0.20.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.21.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
index ecb650de81..91009b675d 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.data.transfer
- 1.0.20-SNAPSHOT
+ 1.0.21-SNAPSHOT
eclipse-plugin
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferServlet.java b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferServlet.java
index ba9d730409..f787740570 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferServlet.java
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferServlet.java
@@ -1,18 +1,17 @@
package io.cloudbeaver.service.data.transfer.impl;
import io.cloudbeaver.DBWebException;
-import io.cloudbeaver.server.CBPlatform;
-import io.cloudbeaver.server.CBApplication;
import io.cloudbeaver.model.session.WebSession;
+import io.cloudbeaver.server.CBApplication;
+import io.cloudbeaver.service.WebServiceServletBase;
import io.cloudbeaver.service.data.transfer.DBWServiceDataTransfer;
+import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferProcessorDescriptor;
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferRegistry;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
@@ -20,69 +19,56 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-public class WebDataTransferServlet extends HttpServlet {
+public class WebDataTransferServlet extends WebServiceServletBase {
private static final Log log = Log.getLog(WebDataTransferServlet.class);
- private final CBApplication application;
private final DBWServiceDataTransfer dtManager;
public WebDataTransferServlet(CBApplication application, DBWServiceDataTransfer dtManager) {
- this.application = application;
+ super(application);
this.dtManager = dtManager;
}
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- try {
- String dataFileId = request.getPathInfo();
- if (CommonUtils.isEmpty(dataFileId)) {
- throw new DBWebException("Data ID not specified");
- }
- while (dataFileId.startsWith("/")) {
- dataFileId = dataFileId.substring(1);
- }
+ protected void processServiceRequest(WebSession session, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException {
+ String dataFileId = request.getPathInfo();
+ if (CommonUtils.isEmpty(dataFileId)) {
+ throw new DBWebException("Data ID not specified");
+ }
+ while (dataFileId.startsWith("/")) {
+ dataFileId = dataFileId.substring(1);
+ }
- WebSession webSession = CBPlatform.getInstance().getSessionManager().findWebSession(request);
- if (webSession == null) {
- throw new DBWebException("No active session");
- }
- WebDataTransferSessionConfig dtConfig = WebDataTransferUtils.getSessionDataTransferConfig(webSession);
- WebDataTransferTaskConfig taskInfo = dtConfig.getTask(dataFileId);
- if (taskInfo == null) {
- throw new DBWebException("Session task '" + dataFileId + "' not found");
- }
- DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(taskInfo.getParameters().getProcessorId());
- if (processor == null) {
- throw new DBWebException("Wrong data processor '" + taskInfo.getParameters().getProcessorId() + "'");
- }
- String fileName = taskInfo.getExportFileName();
- if (!CommonUtils.isEmpty(fileName)) {
- fileName += "." + WebDataTransferUtils.getProcessorFileExtension(processor);
- } else {
- fileName = taskInfo.getDataFileId();
- }
+ WebDataTransferSessionConfig dtConfig = WebDataTransferUtils.getSessionDataTransferConfig(session);
+ WebDataTransferTaskConfig taskInfo = dtConfig.getTask(dataFileId);
+ if (taskInfo == null) {
+ throw new DBWebException("Session task '" + dataFileId + "' not found");
+ }
+ DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(taskInfo.getParameters().getProcessorId());
+ if (processor == null) {
+ throw new DBWebException("Wrong data processor '" + taskInfo.getParameters().getProcessorId() + "'");
+ }
+ String fileName = taskInfo.getExportFileName();
+ if (!CommonUtils.isEmpty(fileName)) {
+ fileName += "." + WebDataTransferUtils.getProcessorFileExtension(processor);
+ } else {
+ fileName = taskInfo.getDataFileId();
+ }
- File dataFile = taskInfo.getDataFile();
+ File dataFile = taskInfo.getDataFile();
- response.setHeader("Content-Type", processor.getContentType());
- response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
- response.setHeader("Content-Length", String.valueOf(dataFile.length()));
+ response.setHeader("Content-Type", processor.getContentType());
+ response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
+ response.setHeader("Content-Length", String.valueOf(dataFile.length()));
- try (InputStream is = new FileInputStream(dataFile)) {
- IOUtils.copyStream(is, response.getOutputStream());
- }
+ try (InputStream is = new FileInputStream(dataFile)) {
+ IOUtils.copyStream(is, response.getOutputStream());
+ }
- // TODO: cleanup export files ASAP?
- if (false) {
- dtConfig.removeTask(taskInfo);
- }
-
- //response.ok(HttpServletResponse.SC_BAD_REQUEST, "Not implemented");
- } catch (Exception e) {
- log.error(e);
- response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Error reading data: " + e.getMessage());
- return;
+ // TODO: cleanup export files ASAP?
+ if (false) {
+ dtConfig.removeTask(taskInfo);
}
}
diff --git a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferUtils.java b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferUtils.java
index 79c88ef71f..40641112cf 100644
--- a/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferUtils.java
+++ b/server/bundles/io.cloudbeaver.service.data.transfer/src/io/cloudbeaver/service/data/transfer/impl/WebDataTransferUtils.java
@@ -6,9 +6,7 @@ import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferProcessorDescriptor;
import org.jkiss.utils.CommonUtils;
-import javax.servlet.http.HttpServlet;
-
-public class WebDataTransferUtils extends HttpServlet {
+class WebDataTransferUtils {
private static final Log log = Log.getLog(WebDataTransferUtils.class);
diff --git a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
index 549db24974..de411c7e2f 100644
--- a/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
+++ b/server/bundles/io.cloudbeaver.service.metadata/META-INF/MANIFEST.MF
@@ -3,8 +3,8 @@ Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: io.cloudbeaver.service.metadata;singleton:=true
-Bundle-Version: 1.0.23.qualifier
-Bundle-Release-Date: 20210301
+Bundle-Version: 1.0.24.qualifier
+Bundle-Release-Date: 20210322
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
diff --git a/server/bundles/io.cloudbeaver.service.metadata/pom.xml b/server/bundles/io.cloudbeaver.service.metadata/pom.xml
index 7e8815d452..1a13cfa685 100644
--- a/server/bundles/io.cloudbeaver.service.metadata/pom.xml
+++ b/server/bundles/io.cloudbeaver.service.metadata/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.service.metadata
- 1.0.23-SNAPSHOT
+ 1.0.24-SNAPSHOT
eclipse-plugin
diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
index af41c0fac8..1fd636359b 100644
--- a/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
+++ b/server/features/io.cloudbeaver.ce.drivers.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
index 2c1800e07d..dd3880deed 100644
--- a/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
+++ b/server/features/io.cloudbeaver.ce.drivers.feature/pom.xml
@@ -9,6 +9,6 @@
../
io.cloudbeaver.ce.drivers.feature
- 1.0.43-SNAPSHOT
+ 1.0.44-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.product.ce.feature/feature.xml b/server/features/io.cloudbeaver.product.ce.feature/feature.xml
index ad22197b8f..3bc4178b47 100644
--- a/server/features/io.cloudbeaver.product.ce.feature/feature.xml
+++ b/server/features/io.cloudbeaver.product.ce.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.product.ce.feature/pom.xml b/server/features/io.cloudbeaver.product.ce.feature/pom.xml
index a9268986cd..1b400dadee 100644
--- a/server/features/io.cloudbeaver.product.ce.feature/pom.xml
+++ b/server/features/io.cloudbeaver.product.ce.feature/pom.xml
@@ -10,7 +10,7 @@
../
io.cloudbeaver.product.ce.feature
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.sample.feature/feature.xml b/server/features/io.cloudbeaver.sample.feature/feature.xml
index 726eadfca5..b1283e5bb8 100644
--- a/server/features/io.cloudbeaver.sample.feature/feature.xml
+++ b/server/features/io.cloudbeaver.sample.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.sample.feature/pom.xml b/server/features/io.cloudbeaver.sample.feature/pom.xml
index 0e1e0ebc17..e12ff598a6 100644
--- a/server/features/io.cloudbeaver.sample.feature/pom.xml
+++ b/server/features/io.cloudbeaver.sample.feature/pom.xml
@@ -9,6 +9,6 @@
../
io.cloudbeaver.sample.feature
- 1.0.23-SNAPSHOT
+ 1.0.24-SNAPSHOT
eclipse-feature
diff --git a/server/features/io.cloudbeaver.server.feature/feature.xml b/server/features/io.cloudbeaver.server.feature/feature.xml
index 1eb306241d..f7c355255c 100644
--- a/server/features/io.cloudbeaver.server.feature/feature.xml
+++ b/server/features/io.cloudbeaver.server.feature/feature.xml
@@ -2,7 +2,7 @@
diff --git a/server/features/io.cloudbeaver.server.feature/pom.xml b/server/features/io.cloudbeaver.server.feature/pom.xml
index 9abe26a146..8a6c966665 100644
--- a/server/features/io.cloudbeaver.server.feature/pom.xml
+++ b/server/features/io.cloudbeaver.server.feature/pom.xml
@@ -10,6 +10,6 @@
../
io.cloudbeaver.server.feature
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
eclipse-feature
diff --git a/server/pom.xml b/server/pom.xml
index a04d099b0e..e0a851729e 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -19,7 +19,7 @@
CloudBeaver CE
- 20.0.4
+ 20.0.5
diff --git a/server/product/provided-sample/DBeaverWebProvidedSample.product b/server/product/provided-sample/DBeaverWebProvidedSample.product
index 538d0515d2..0871c94737 100644
--- a/server/product/provided-sample/DBeaverWebProvidedSample.product
+++ b/server/product/provided-sample/DBeaverWebProvidedSample.product
@@ -1,7 +1,7 @@
-
+
diff --git a/server/product/provided-sample/pom.xml b/server/product/provided-sample/pom.xml
index 00a643e0f0..fe2cdb58f7 100644
--- a/server/product/provided-sample/pom.xml
+++ b/server/product/provided-sample/pom.xml
@@ -9,7 +9,7 @@
1.0.0-SNAPSHOT
../../
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
provided-sample
eclipse-repository
Cloudbeaver Provided Sample Product
diff --git a/server/product/web-server/CloudbeaverServer.product b/server/product/web-server/CloudbeaverServer.product
index 6c27e09d11..87d48d544e 100644
--- a/server/product/web-server/CloudbeaverServer.product
+++ b/server/product/web-server/CloudbeaverServer.product
@@ -2,7 +2,7 @@
diff --git a/server/product/web-server/pom.xml b/server/product/web-server/pom.xml
index 282b6bac41..0074d49057 100644
--- a/server/product/web-server/pom.xml
+++ b/server/product/web-server/pom.xml
@@ -9,7 +9,7 @@
1.0.0-SNAPSHOT
../../
- 20.0.4-SNAPSHOT
+ 20.0.5-SNAPSHOT
web-server
eclipse-repository
Cloudbeaver Server Product
diff --git a/webapp/package.json b/webapp/package.json
index f1d2558599..c0379fba06 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -45,7 +45,7 @@
"reakit": "^1.3.4",
"reflect-metadata": "^0.1.13",
"reshadow": "^0.0.1-alpha.78",
- "typescript": "^4.1.3"
+ "typescript": "^4.2.3"
},
"dependencies": {}
}
\ No newline at end of file
diff --git a/webapp/packages/core-blocks/package.json b/webapp/packages/core-blocks/package.json
index 7ab2888983..d09851ae2e 100644
--- a/webapp/packages/core-blocks/package.json
+++ b/webapp/packages/core-blocks/package.json
@@ -15,7 +15,7 @@
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
},
"dependencies": {
- "go-split": "^1.x.x",
+ "go-split": "^2.x.x",
"sanitize-html": "^1.x.x",
"react-sanitized-html": "^2.x.x"
},
diff --git a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts
index 35aa33a23c..932fc8e0a9 100644
--- a/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts
+++ b/webapp/packages/core-blocks/src/Containers/BASE_CONTAINERS_STYLES.ts
@@ -13,10 +13,10 @@ import { composes } from '@cloudbeaver/core-theming';
export const BASE_CONTAINERS_STYLES = composes(
css`
Group {
- composes: theme-background-surface from global;
+ composes: theme-background-surface theme-text-on-surface from global;
}
ColoredContainer {
- composes: theme-background-secondary from global;
+ composes: theme-background-secondary theme-text-on-secondary from global;
}
`,
css`
diff --git a/webapp/packages/core-blocks/src/FormControls/TextareaNew.tsx b/webapp/packages/core-blocks/src/FormControls/TextareaNew.tsx
index 9fa6016c80..baa60739bc 100644
--- a/webapp/packages/core-blocks/src/FormControls/TextareaNew.tsx
+++ b/webapp/packages/core-blocks/src/FormControls/TextareaNew.tsx
@@ -10,7 +10,7 @@ import { observer } from 'mobx-react-lite';
import { useCallback, useContext } from 'react';
import styled, { css, use } from 'reshadow';
-import { useStyles } from '@cloudbeaver/core-theming';
+import { ComponentStyle, useStyles } from '@cloudbeaver/core-theming';
import type { ILayoutSizeProps } from '../Containers/LayoutProps';
import { baseFormControlStylesNew } from './baseFormControlStylesNew';
@@ -20,16 +20,33 @@ const styles = css`
textarea {
line-height: 19px;
}
+ field[|embedded] {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ & textarea {
+ border-radius: 0 !important;
+ height: 100%;
+ resize: none !important;
+ }
+ }
field-label {
display: block;
padding-bottom: 10px;
composes: theme-typography--body1 from global;
font-weight: 500;
+
+ &:empty {
+ display: none;
+ }
}
`;
-type BaseProps = Omit, 'onChange'> & ILayoutSizeProps & {
+type BaseProps = Omit, 'onChange' | 'style'> & ILayoutSizeProps & {
mod?: 'surface';
+ style?: ComponentStyle;
+ embedded?: boolean;
};
type ControlledProps = BaseProps & {
@@ -53,6 +70,7 @@ interface TextareaType {
export const TextareaNew: TextareaType = observer(function TextareaNew({
name,
+ style,
value: controlledValue,
state,
children,
@@ -61,6 +79,7 @@ export const TextareaNew: TextareaType = observer(function TextareaNew({
medium,
large,
mod,
+ embedded,
onChange = () => {},
...rest
}: ControlledProps | ObjectProps) {
@@ -80,8 +99,8 @@ export const TextareaNew: TextareaType = observer(function TextareaNew({
const value = state ? state[name] : controlledValue;
- return styled(useStyles(baseFormControlStylesNew, styles))(
-
+ return styled(useStyles(baseFormControlStylesNew, styles, style))(
+
{children}