Compare commits

...
292 Commits
Author SHA1 Message Date
AinurandDaria Marutkina 5a8660a37f CB-4154 rp add te role header and auth log (#2117) (#2123)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-11-10 20:04:17 +03:00
serge-rider 1ca883bf64 23.2.4 version bump 2023-11-01 21:11:57 +01:00
serge-rider e3608a2504 23.2.4 version bump 2023-11-01 20:21:03 +01:00
b3c1cebd69 CB-4097 fix: set user role when creation user (#2101)
* CB-4097 fix: set user role when creation user

* CB-4097 fix: validate role correctly

* CB-4097 validate team before deleting

* CB-4097 fix: detect auth role correctly

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2023-11-01 22:09:20 +03:00
0610759ac2 CB-4049. Added support https on Jetty level (#2093)
* CB-4049. Added support https on Jetty level

* CB-4049. Update configuration files

* CB-4049. Added comments for SSl configuration

* CB-4049. Renamed configuration param

* CB-4049 use same port for ssl

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2023-11-01 20:05:16 +03:00
Serge RiderandDaria Marutkina ff770a1270 dbeaver/pro#2008 Patch server start scripts (#2094)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-11-01 18:39:34 +03:00
AinurandDaria Marutkina 4c7b9fca95 CB-4127 ssl show certificates (#2097)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-11-01 16:50:39 +03:00
AlexeyandEvgeniaBzzz f98b9aa989 CB-4149 fix: easy config localization (#2103)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-31 18:57:34 +03:00
Alexander Skoblikov 1ecdced23e CB-4186 fix rm api (#2104) 2023-10-31 18:57:25 +03:00
cb60358ae6 Cb 4112 open scripts datasets from virtual file systems (#2089)
* CB-4125 use base path

* CB-4112 feat: read objectId

* CB-4145 add required auth to fs system api

* CB-4145 move feature

* CB-4112 feat: open scripts from file systems

* CB-4125 improve file reading

* CB-4112 refactor: naming

* CB-4112 update schema

* CB-4112 fs by id gql

* CB-4112 unique fs id

* CB-4112 fix gql schema

* CB-4112 fix gql schema

* CB-4112 update manifest

* CB-4112 feat: require authentication for nav-tree

---------

Co-authored-by: Aleksey Potsetsuev <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-31 17:18:32 +03:00
alexandEvgeniaBzzz 0f9e7b650c CB-4005 add wrap mode (#2081)
* CB-4005 add wrap mode

* CB-4005 save wrap state in user settings

* CB-4005 add tooltips

* CB-4005 review fixes

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-31 17:16:09 +03:00
AlexeyandDaria Marutkina b2eab058c9 CB-3846 feat: allow an administrator to use data export (#2095)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-31 15:57:27 +03:00
4f0fa25d83 CB-4123 servlet for upload download fs files (#2078)
* CB-4123 servlet for upload download fs files

* CB-4123 use variables in fs servlet

* CB-4123 use parameter nodepath in get

* CB-4123 upload file fix

* CB-4123 use project id and uri

* CB-4124 add upload/download context actions

* CB-4124 move fs extension to EE

* CB-4124 export NavigationNodeControl styles

* CB-4123 validate project permissions

* CB-4123 code style fix

* CB-4124 keep loader close to the title in notification

* CB-4123 prettify error

* CB-4113 resolve conflicts

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-30 20:10:53 +03:00
a3bdfb68fe CB-3778-bug-use-oracle-as-internal-db (#1920)
* CB-3778 fetch limit fix for oracle and sql server

* CB-3778 get offset limit part from sql dialect

* CB-3778 offset limit order fix

* CB-3778 schemas fix

---------

Co-authored-by: Mikhailov Grigorii <49814763+ggxed@users.noreply.github.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-30 19:59:05 +03:00
AlexeyandEvgeniaBzzz 584dd1ce4f CB-4096 fix: synchronize user info data update (#2096)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-27 20:11:39 +03:00
Serge Rider 5255ee96db Remove redundant config 2023-10-27 16:26:40 +02:00
alexandEvgeniaBzzz e68c44ed73 CB-4019 update output log icon (#2090)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-27 12:32:36 +03:00
Alexander Skoblikov e4f01a3fa8 rm fix (#2091) 2023-10-26 17:23:20 +03:00
Alexey a5c9073e6f CB-4112-open-scripts-datasets-from-virtual-file-systems (#2088) 2023-10-25 19:23:54 +03:00
Alexander Skoblikov b7d32ad676 CB-4125 use base path (#2087) 2023-10-25 19:18:33 +03:00
Alexander Skoblikov a520aa1f20 CB-4125 add objectId to gql navigator model (#2085) 2023-10-25 18:19:03 +03:00
Serge Rider 8e4c0c11a4 dbeaver/pro#1978 SSO sign out (#2032) 2023-10-25 18:17:42 +03:00
Alexander Skoblikov 72b3838fa9 fix package folders (#2083) 2023-10-25 15:41:47 +03:00
alexandDaria Marutkina df9de51bda CB-4128 review fixes (#2082)
* CB-4128 review fixes

* CB-4128 declare styles once

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-25 13:34:59 +03:00
Alexander SkoblikovandEvgeniaBzzz 390f53f36b CB-4161 auth fix (#2084)
* CB-4161 auth fix

* CB-4161 validate custom config status

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-24 19:54:28 +03:00
alexandDaria Marutkina d3cf9e3938 CB-4035 do not show confirm if it is only output tab (#2079)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-24 18:11:02 +03:00
alexandEvgeniaBzzz 97dc309bcb CB-4022 make filter case insensitive (#2080)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-24 18:10:45 +03:00
AinurandDaria Marutkina 6c609d7f62 CB-4139 update clickhouse driver (#2070)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-24 16:51:00 +03:00
AinurandEvgeniaBzzz f67835d2d2 CB-2700 delimeter support (#2068)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-24 16:49:51 +03:00
DenisSinelnikovandEvgeniaBzzz 98197c8829 CB-4099. Create logic for save comfig and user for CB TE. (#2067)
* CB-4099. Create logic for save comfig and user for CB TE.

* CB-4099. Fixed checkstyle

* CB-4099. Refactor after review

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-24 15:46:55 +03:00
Alexey 997936328e fix(core-resource): error getter (#2077) 2023-10-23 22:53:24 +03:00
EvgeniaBzzz f7832b56fa Merge pull request #2076 from dbeaver/EvgeniaBzzz-patch-1
CB_2323 chore: update README
2023-10-23 13:32:50 +03:00
EvgeniaBzzz 81ce6b6ac7 CB_2323 chore: update README 2023-10-23 13:32:35 +03:00
Alexey 518410c2e8 Fix/cb-4141/localization (#2071) (#2075) 2023-10-20 19:51:04 +03:00
Alexander Skoblikov 4645a8e3d1 Cb 3959 UI file system navigator view (#2069)
* CB-4061 file systems feature

* CB-4061 return rm fs navigator nodes

* CB-3959 fix tests

* CB-3959 encode spaces in rm uri
2023-10-20 19:14:24 +03:00
DenisSinelnikov be59a4dab9 Hotfix 4144 validate blob (#2072)
* CB-4144. Fix regex
2023-10-20 16:29:31 +03:00
Alexander Skoblikov 3a92d7d23d CB-3930 use rm provider for rm fs (#2038) 2023-10-19 13:26:55 +03:00
d44e6b4e7a CB-3564 multi server license (#2062)
* CB-3564 fix: localization

* CB-3984 wip

* CB-3984 multi instance license

* CB-3564 feat: external users provider

* CB-3984 server init fix

* CB-3564 feat: load resource for administration users management

* CB-3984 force enable imported user

---------

Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-18 21:17:16 +03:00
DenisSinelnikov d87115d753 CB-3704. Validate file name (#2065)
* CB-3704. Validate file name

* CB-3704. Revert imports

* CB-3704. Refactor after review

* CB-3704. Fixed error message if files not created.

* CB-3074. Remove constant to Servlet
2023-10-18 15:42:29 +03:00
245d49b892 CB-4098 add prompt dialog to the sql editor (#2055)
* CB-4098 add prompt dialog to the sql editor

* CB-4098 add api integration

* CB-4046 add events

* CB-4046 fixes after review

* CB-3913 move AI feature to the ee

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-18 13:37:23 +03:00
alexandmr-anton-t 3831abc880 CB-4038 add action icon button (#2064)
* CB-4038 add action icon button

* CB-4038 update styles in image value panel

* CB-4038 keep default styles export

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-10-17 18:34:52 +03:00
Serge Rider e818f1658c dbeaver/pro#1905 UTF-8 is the default file encoding (#2060) 2023-10-17 10:32:43 +03:00
Alexey 739a6f7f11 chore: update version 23.2.3 (#2066) 2023-10-16 23:06:07 +02:00
ab985673b0 CB-3704 feat(plugin-data-viewer): blob uploading (#2027)
* CB-3704 feat(plugin-data-viewer): blob uploading

* CB-3704 fix: check  truncated value correctly

* CB-4051. Added upload big files

* CB-4051. remove unusable files

* CB-3704 feat: upload blobs

* CB-4051. Refactor after discussion with front-end

* CB-4051. Merge develop

* CB-4051. Fixed imports

* CB-3704 fix: upload blobs for new rows

* CB-4051. Fixed added new row with file

* fix: reset editing state

* CB-4051. Fixed after review

* CB-4051. revert

* CB-4051. Fixed doc, imports, style

* CB-4051. Fixed checkstyle

* revert

* CB-4051. Refactor after review, added handler for delete temp folder

* CB-3704 chore: update ts project references

* CB-3704 fix: rename file upload name

* CB-3704. delete comments

* CB-3704. Refactor after review

* CB-3074. Rename job

* CB-3704. Fix save for json

* CB-3704 fix: boolean value representation

* CB-3704 fix: downloadable data detection

* CB-3704 fix: downloadable data detection

* CB-3704. Fixed boolean null value

* CB-3704 fix: truncate long strings for display data

* CB-3704 fix: transform complex values

* CB-3704. Fixed json update

* CB-3704 fix: display value

* CB-3704 fix: data set

* CB-3704 fix: keep content type when editing content values

* CB-3704 feat: add download button for

* CB-3704. Rename event

---------

Co-authored-by: Denis Sinelnikov <denis.sinelnikov@dbeaver.com>
Co-authored-by: DenisSinelnikov <142215442+DenisSinelnikov@users.noreply.github.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-16 16:47:11 +03:00
Alexey abf3e7247c chore: update yarn.lock (#2063) 2023-10-15 23:52:04 +02:00
49f321462e CB-3454 ai (#2033)
* CB-3999 add ai plugin

* CB-3454 review fixes

* CB-3454 gql since directive fix

* CB-3454 update tsconfig

* fix: npm dependencies

* CB-4045 add hint property

* CB-3454 add hints

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-13 17:03:33 +03:00
Serge Rider d0a820d27b dbeaver/pro#1900 tasks virtual fs (#2040)
* dbeaver/pro#1900 Refactor DT and general UI

* dbeaver/pro#1900 Export to external FS implementation
2023-10-12 15:31:09 +03:00
Alexey bd9a18bc50 chore: update vs-code tasks (#2059) 2023-10-12 12:49:03 +02:00
Serge Rider 3fa1130608 23.2.3 version bump 2023-10-12 10:46:20 +02:00
fe2c7b76be feat: migrate form-controls to css modules (#2041)
* feat: migrate form-controls to css modules

* fix: checkbox field styles

* fix: remove old field styles

* fix: styles bugs

* CB-3773 fix: styles

* CB-3773 fix: field description styles

* CB-3773 fix: radio button styles

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-10-10 20:19:40 +03:00
Serge Rider 4344dce700 dbeaver/pro#2000 Java 17 (#2057) 2023-10-10 19:50:48 +03:00
Alexey dc402f1940 fix: jest tests (#2056) 2023-10-10 17:44:39 +02:00
bdcda6a1fb CB-4028 delete/add api for permissions (#2024)
* CB-4028 delete/add api for permissions

* feat: add new subjects connection add and delete methods

* CB-4028 fix method name

* refactor: subject connection permissions

* fix: after review

* fix: after review

* CB-4028 fix: update ts project references

* fix: dependencies cycle

* chore: fix dependencies

* CB-4028 event for delete

* CB-4028 delete object permission event

---------

Co-authored-by: Dmitry Osipov <teunlao@gmail.com>
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-10 18:41:14 +03:00
Alexey baef7fbae6 build: configure browserslist config (#2054) 2023-10-10 11:54:51 +02:00
Serge RiderandAleksandr Skoblikov b52c2788b1 dbeaver/pro#1962 eclipse 2023 09 2 (#2036)
* dbeaver/pro#1962 Servlet API 4.x deps

* dbeaver/pro#1962 Redundant SLF4J dep removed

* dbeaver/pro#1962 SLF4J binding fix + servlet API version

* dbeaver/pro#1962 add cloudbeaver slf4j binding

* dbeaver/pro#1962 Logging

* dbeaver/pro#1962 Logging fix

---------

Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2023-10-10 12:51:39 +03:00
48b9326336 CB-4065 safe context getter (#2043)
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-10 00:06:34 +03:00
Alexey 37d76c428d feat: add more logging (#2052) 2023-10-09 18:26:26 +02:00
Alexey 01bcf9479d fix: resolve npm dependencies (#2050)
* fix: resolve npm dependencies

* fix: types

* chore: add manual frontend cache actin running

* fix: github workflows

* fix: types

* fix: types

* fix: types
2023-10-09 16:25:07 +03:00
Daria Marutkina 31355b81f8 Merge pull request #2051 from dbeaver/dariamarutkina-patch-1
CB_2322 chore: update README
2023-10-09 14:20:04 +02:00
Daria Marutkina 226762c5f9 CB_2322 chore: update README 2023-10-09 14:19:42 +02:00
Serge Rider 6b58613c83 Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2023-10-08 18:31:14 +02:00
Serge Rider e3f04bcbb0 23.2.2 version bump 2023-10-08 18:28:34 +02:00
Alexey c5d0e4bade chore: join build and test workflows (#2049)
* chore: join build and test workflows

* chore: add devel branch cache

* chore: cleanup github actions cache
2023-10-08 00:48:34 +03:00
45335f5dd7 Cb 4082 fix styles bugs (#2042)
* fix: transparent pane

* fix: connection dialog footer styles

* fix: logViewer background

* fix: execution plan style bugs

* fix: action button styles

* fix: action button styles

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-07 23:41:48 +03:00
Alexey ff4c453f8d fix: webpack dev mode (#2048) 2023-10-06 17:29:29 +02:00
Alexey be5bb95154 fix: ts configs (#2047) 2023-10-06 15:35:07 +02:00
Alexey ece5e8f3f1 fix: unix paths (#2046) 2023-10-06 14:35:38 +02:00
Alexey 9dcd287c61 fix: double build (#2045) 2023-10-06 12:13:58 +03:00
Alexey 97b43c044f build: enable source maps (#2044) 2023-10-06 00:27:44 +03:00
Alexey 4550a71298 Refactor CB-3819 resources (#2031)
* CB-3819 refactor: split resources to modules

* CB-3819 refactor: move resource API to separate package

* CB-3819 refactor: move resource API to separate package

* CB-3819 refactor: split to submodules

* CB-3819 chore: update ts configuration

* CB-3819 refactor: move administration top bar to separate plugin

* CB-3819 feat: update tests

* CB-3819 chore: add pre scripts

* CB-3819 fix: prebuild tests-runner

* chore: restore cache for jest-tests github action

* chore: update configs

* chore: add frontend build action

* chore: rename build frontend github action

* chore: include test dependencies

* fix: default product build script

* chore: update github action

* chore: rename validation github action

* chore: update typescript cache key

* chore: update naming for github actions

* chore: run tests on ubuntu

* CB-3819 fix: pre build tasks

* CB-3819 fix: ignore order

* CB-3819 fix: remove prettier from gql sdk
2023-10-05 23:36:54 +03:00
AinurandDaria Marutkina ca4fe0b96d CB-3943 use server name fields for bigtable and spanner (#1978)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-10-04 16:37:03 +03:00
66c1f94464 Cb 3861 Migrate Simple component to CSS modules (#2009)
* feat: migrate Body to css-modules

* feat: migrate Main to css-modules

* feat: migrate AppRefreshButton to css-modules

* feat: migrate Button to css-modules

* feat: migrate Cell to css-modules

* feat: migrate Code to css-modules

* feat: migrate DisplayError to css-modules

* feat: migrate ErrorBoundary to css-modules

* feat: migrate ExceptionMessage to css-modules

* feat: migrate Iframe to css-modules

* feat: migrate InfoItem to css-modules

* feat: migrate Link to css-modules

* feat: migrate StatusMessage to css-modules

* feat: migrate TextPlaceholder to css-modules

* feat: migrate TimerIcon to css-modules

* feat: migrate UploadArea to css-modules

* feat: migrate ConnectionMark to css-modules

* feat: Expandable ConnectionMark to css-modules

* feat: migrate RightArea, Split styles to css-modules

* feat: fixes after review

* feat: fixes after review

* feat: fixes after review

* feat: fixes after review

* fix: fixes after review

* fix: iframe style import

* fix: fix ui bugs after tests

* fix: versionChecker styles

* fix: properties-table add button styles

* fix: table-viewer border styles

* CB-3861 fix: styles

* CB-3861 fix: styles

* fix: fix test error

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Aleksey Potsetsuev <wrouds@gmail.com>
2023-10-04 16:21:23 +03:00
Dmitriy Osipov a9c2d8830a fix: add 100 ms interval for tracking windows (#2037) 2023-10-03 18:52:17 +03:00
Alexander Skoblikov 1f8dd642bc CB-3930 fs gql api (#2026)
* CB-3930 fs gql model

* CB-3930 fs manager

* CB-3930 add fs modules to server feature

* CB-3930 fs per project

* CB-3930 fix rm file store

* CB-3930 fixes
2023-10-03 16:52:14 +03:00
DenisSinelnikovandEvgeniaBzzz c874b4b440 CB-3839. Added async error events messages for te (#2006)
* CB-2551. Fixed additional auth for disabled user

* CB-3839. Added async error events messages for te

* CB-3839. Remove comments, fixed checkstyle

* CB-3839. Refactor after review

* CB-3839. Refactor after review

* CB-3839. Refactor after review, updated logic

* CB-3883. Fixed Error Logs

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-10-03 13:23:45 +03:00
Serge Rider c31826f830 23.2.2 version bump 2023-10-02 11:27:50 +02:00
Alexander Skoblikov e00ca87364 improve auth test (#2030) 2023-09-29 20:30:34 +03:00
Alexander Skoblikov e56247b837 Revert "improve rm test timeouts (#2028)" (#2029)
This reverts commit 4e25a42b1c.
2023-09-29 20:29:19 +03:00
Alexander Skoblikov 4e25a42b1c improve rm test timeouts (#2028) 2023-09-29 20:28:42 +03:00
AlexeyandEvgeniaBzzz 0d41713c2d CB-3456 refactor: user form (#2010)
* CB-3456 chore: cleanup users administration

* CB-3456 chore: add label for user credentials column

* CB-3456 chore: add deprecation message to reshadow system

* CB-3456 chore: add deprecation message to ComponentStyle

* CB-3456 refactor: user form

* CB-3456 fix: eslint problems

* CB-3456 fix: after review

* CB-3456 fix: base form localization

* CB-3456 fix: remove unused import

* CB-3456 fix: user default team assignment

* CB-3456 chore: update git indexes

* CB-3456 fix: imports

* CB-3456 fix: enable user by default

* CB-3456 refactor: implement FormPart

* CB-3456 fix: make sh executable

* CB-3456 fix: make sh executable

* CB-3456 fix: handle form part exceptions on save

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-28 16:28:28 +03:00
AinurandEvgeniaBzzz c58e62c90e CB-2153 update values of tables with join fix (#1961)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-28 14:05:00 +03:00
alex 6da5f3b0e4 CB-4059 do not verify the SSL Certificate of the target server in dev mode (#2025) 2023-09-28 13:47:29 +03:00
alexandAlexey 713082215f CB-3197 add interface comments (#2018)
* CB-3197 add interface comments

* CB-3197 make comments cleaner

* CB-3197 add comment for the indeterminateSelected

* CB-3197 fix code style

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2023-09-28 13:46:02 +03:00
571d6b7c0a CB-3864 migrate tree to css modules (#2003)
* CB-3864 migrate tree to css modules

* CB-3864 migrate extra components

* CB-3864 review fixes

* CB-3864 move editing and dragging props from base nav components

* CB-3864 add styles to renderer

* CB-3864 fix aws styles

* CB-3864 remove padding in projects renderer

* CB-3864 fix node hover effect

* CB-3864 remove custom tags

* CB-3864 remove config changes

* CB-3864 review fixes

* CB-3864 move NavigationNodeControl styles closer to the component

* CB-3864 chore: code cleanup

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-09-28 02:02:49 +03:00
Alexander Skoblikov a2d9fddc5e CB-3930 redesign resource management api (#1998)
* CB-3946 rm nio api

* CB-3946 read/write nio api

* CB-3946 nio tests
2023-09-27 16:30:37 +03:00
Serge Rider 2e71cfdf87 dbeaver/pro#1925 Profile source model (#1996) 2023-09-26 20:41:17 +03:00
alex c4975475a1 CB-3898 add base CachedMapResource tests (#2013)
* CB-3898 add base CachedMapResource tests

* CB-3908 add tests for the handlers

* CB-3908 add error tests

* CB-3908 add initial tests for the CachedDataResource

* CB-3908 remove extra test

* CB-3908 add clear data test

* CB-3908 add CachedTreeResource tests

* CB-3908 review fixes

* CB-3908 transform mock data to getters
2023-09-26 18:27:00 +03:00
alexandEvgeniaBzzz 0d941b61c8 CB-4052 await login properly (#2022)
* CB-4052 await login properly

* CB-4052 make message cleaner

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-26 16:04:02 +03:00
alexandEvgeniaBzzz 3b0e31614c CB-4017 make boolean fields larger (#2021)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-26 16:03:41 +03:00
alex 542217cc16 CB-2439 remove save creds options from templates (#2020) 2023-09-25 20:07:16 +03:00
EvgeniaBzzz 75b293d6a9 Merge pull request #2019 from dbeaver/EvgeniaBzzz-patch-4
CB_2321 chore: update README
2023-09-25 16:23:12 +03:00
EvgeniaBzzz ad27eec4a7 CB_2321 chore: update README 2023-09-25 16:14:34 +03:00
Alexey 55ab736104 fix: eslint parser (#2016) 2023-09-22 18:50:58 +03:00
Alexey 9384877bb0 fix: dependency alert (#2015) 2023-09-22 18:34:04 +03:00
Alexey 63c7c6feb1 fix: ignore typescript error (#2014) 2023-09-22 18:15:24 +03:00
Alexey 6eaafd6e2a dev: update chrome vs-code configuration (#2011) 2023-09-21 17:44:16 +03:00
serge-rider 0a88cbdb50 Version 23.2.1 bump 2023-09-20 20:07:30 +02:00
AinurandEvgeniaBzzz 1a434adb3d CB-3945 add subject permissions changed events (#1974)
* CB-3945 add subject permissions changed events

* CB-3945 remove parameter from subject event

* CB-3945 code style fix

* CB-3945 check rm admin permission

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-20 19:45:10 +03:00
8a685ef47e Cb 1036 server output log sql editor (#1999)
* CB-2551. Fixed additional auth for disabled user

* CB-3923. Added output reader logs

* CB-3923. Added output reader logs

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3923. Refactor after review

* CB-3924: add show output button

* CB-3924: add output event handler and resource

* CB-3924: add server output logs panel

* CB-3924: fix bugs

* CB-3923. Fixed checkstyle

* CB-3924: fixes after review

* CB-3923. Refactor after review

* CB-3924: fixes after review

* CB-3924: add line wrapper extension for editor

* CB-3923. Refactor after review

* CB-3924: show output logs for current context

* CB-3924: fixes after review

* CB-3924: add output logs icon

* CB-3924: fixes after review

* CB-3924: fixes after review

* CB-3924: fixes after review

* CB-3924: fix bug with not updated menus

* CB-3924. Fix boolean type

---------

Co-authored-by: Dmitry Osipov <teunlao@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-20 13:02:29 +03:00
AlexeyandEvgeniaBzzz a981d37a2d CB-3936 feat: multilane label checkboxes (#1970)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-18 13:35:07 +03:00
Alexey cba58e0c15 chore: update yarn lock (#2001) 2023-09-14 11:39:16 +03:00
Alexeyandmr-anton-t edc15b664f CB-3678 feat: update react-data-grid (#1997)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-09-14 11:31:31 +03:00
Dmitriy OsipovandDaria Marutkina 39dfa3e05d CB-3862: migrate folder-explorer to css-modules (#1979)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-09-13 16:39:55 +03:00
alexandmr-anton-t 320d7e84ee CB-3860 migrate dialog to css modules (#1994)
* CB-3860 migrate dialog to css modules

* CB-3860 refactor all dialogs styles

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-09-13 16:39:27 +03:00
Dmitriy Osipov 7ea8befbe4 CB-3863: migrate overlay to css-modules (#1976) 2023-09-13 15:07:42 +03:00
alex d8ade2a09c CB-3859 migrate table from reshadow to css modules (#1989) 2023-09-13 15:07:02 +03:00
Alexey 5030094f1f CB-3598 fix: react rendering errors (#1990) 2023-09-13 15:04:45 +03:00
Dmitriy OsipovandEvgeniaBzzz 4a04023062 Cb 3910 focus fix (#1962)
* CB-3910: fix focusable elements selector

* CB-3910: update focus when ref changed

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-09-13 12:54:36 +03:00
alex 751a9c7893 Chore/cb 3858 update dependencies (#1986)
* CB-3858 update core-cli & codemirror

* CB-3858 remove @parcel/watcher

* CB-3858 update core packages
2023-09-12 12:42:36 +03:00
alex 006dd209ee CB-3998 delete unsupported actions in updateResults (#1993) 2023-09-12 10:47:52 +03:00
Serge Rider 4e0c23ef30 Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2023-09-07 14:56:49 +02:00
Serge Rider da6a84c15a Constants reuse 2023-09-07 14:56:32 +02:00
Dmitriy Osipov ff32a5a577 CB-3970: move error handlers closer to components (#1983)
* CB-3970: move error handlers closer to components

* CB-3970: handle errors of opening navNode

* CB-3970 fix: interrupt executor instead of throwing error
2023-09-07 14:42:42 +03:00
Alexey f479d8410a CB-3957 fix: verify change availability flags (#1988) 2023-09-07 14:41:41 +03:00
Serge Rider d3054e26ce dbeaver/pro#1872 Delete redundant config files 2023-09-04 16:19:54 +02:00
EvgeniaBzzz 32baba6434 Merge pull request #1982 from dbeaver/EvgeniaBzzz-patch-3
CB_2320 chore: update README
2023-09-04 13:41:19 +03:00
EvgeniaBzzz 00f45ae455 CB_2320 chore: update README 2023-09-04 13:37:00 +03:00
Alexey beed8ff9ae CB-3953 fix: git description message (#1981) 2023-09-04 11:30:14 +03:00
Alexey cbc98c5722 CB-3951 fix: check query history permissions (#1977) 2023-09-01 16:30:29 +03:00
DenisSinelnikovandEvgeniaBzzz 45266974ab CB-2551. Fixed additional auth for disabled user (#1963)
* CB-2551. Fixed additional auth for disabled user

* CB-2551. Fixed additional auth for disabled user

* CB-2551. Fixed additional auth for disabled user

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-31 18:50:26 +03:00
AlexeyandDaria Marutkina 232dfb4ed4 CB-3891 feat: inverse git sync data (#1965)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-31 15:41:04 +03:00
Alexander SkoblikovandEvgeniaBzzz a94ca5e635 CB-3931 copy params only for test connection (#1969)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-30 18:08:04 +03:00
Alexander Skoblikov 0767d0d3a1 CB-3935 create project for new users correctly (#1971) 2023-08-30 17:59:01 +03:00
Alexey a21ebf837c fix: windows vscode workspace (#1968)
* fix: windows vscode workspace

* fix: dev commands
2023-08-30 13:12:59 +03:00
f1507c3a7d CB-3602 fix: sql context management (#1942)
* CB-3602 fix: sql context management

* CB-3711 fix: sql context lifecycle

* CB-3602 Cleanup SQL processors/contexts on connection close

* CB-3602 Cleanup SQL processors/contexts on connection close

* CB-3602 fix: log sql script parsing errors

* CB-3602 fix: sql context info convertation

* CB-3602 fix: data concurrency loading

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-29 22:53:05 +03:00
Dmitriy Osipov 773edfc9c0 CB-3925: update product info dialog styles (#1966) 2023-08-29 22:36:45 +03:00
Alexander SkoblikovandEvgeniaBzzz 68abf6051a CB-3874 send password change event correctly (#1964)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-29 22:35:51 +03:00
AinurandDaria Marutkina 8d5a61e04e CB-3878 remove rm listener if user session is expired (#1960)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-29 17:03:28 +03:00
AinurandDmitry Osipov 4d060ed746 CB-3045 delete team with users (#1943)
* CB-3045 delete team with users

* CB-3905 add force flag for deleting team

* CB-3045: delete teams even they may contain users

* CB-3045: update delete team confirmation message

---------

Co-authored-by: Dmitry Osipov <teunlao@gmail.com>
2023-08-29 17:02:44 +03:00
Dmitriy OsipovandDaria Marutkina 534b02d5ee CB-3178: fix navigation tree tools styles (#1959)
* CB-3178: fix navigation tree tools styles

* CB-3178: refactoring css-modules

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-29 12:22:01 +03:00
Dmitriy OsipovandEvgeniaBzzz 7a3b17081c CB-3726: fix duplicated notifications (#1946)
* CB-3726: fix duplicated notifications

* CB-3726 add threshold to show notifications with same error

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-28 20:26:23 +03:00
alexandEvgeniaBzzz 15430d5c62 CB-3919 add icons smaller (#1958)
* CB-3919 add icons smaller

* CB-3919 use standart icon size

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-28 20:26:00 +03:00
Serge RiderandDaria Marutkina 619d4754cb dbeaver/pro#1885 NTLM + TE authentication UI enhancements + IDP icons fix (#1954)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-28 13:41:37 +03:00
5389d4a5c6 CB-3662 unschedule tasks with invalid project (#1908)
Co-authored-by: Dziyana <31996417+uslss@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-28 12:06:12 +03:00
AlexeyandEvgeniaBzzz b2d7f12a11 CB-3651 fix: container resource key validation (#1956)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-25 18:50:47 +03:00
AlexeyandEvgeniaBzzz 8d8ac0b5df CB-3189 fix: add auth configuration link (#1950)
* CB-3189 fix: add auth configuration link

* CB-3189 fix: infinity rerenders

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-25 18:40:07 +03:00
AlexeyandEvgeniaBzzz 6affba2d40 CB-3889 fix: useResource sync (#1957)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-25 18:39:52 +03:00
AlexeyandDaria Marutkina 7769e1c7bf CB-3895 fix: columns dnd errors (#1947)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-25 16:37:31 +03:00
3a889769b4 CB-3810. Fixed refresh button for update for 2 or more session. (#1949)
* CB-3810. Fixed refresh button for update for 2 or more session.

* CB-3810. Fixed refresh button for update for 2 or more session.

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-25 16:36:35 +03:00
alexandEvgeniaBzzz b8968ab349 CB-3896 always refetch auth tokens on login/logout (#1953)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-25 15:22:56 +03:00
Serge Rider f0156ae069 Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2023-08-25 11:34:56 +02:00
Serge Rider a81b81ff2d 23.2.0 version bump 2023-08-25 11:33:45 +02:00
alexandDaria Marutkina 65e1b25519 CB-2694 do not show invalid user teams state (#1948)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-25 11:16:22 +02:00
alexandEvgeniaBzzz d2b72d3617 Cb 3880 auth dialog title changes (#1944)
* CB-3880 rework auth dialog titles

* CB-3880 add fallback for the empty string

* CB-3880 add 'additional' prefix

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-25 11:15:24 +02:00
alex 3fa9f5276f CB-3919 wrap mergeRefs in useCallback (#1952) 2023-08-25 11:49:44 +03:00
DenisSinelnikovandDaria Marutkina 8b1a75eef6 CB-3449. Fixed formatting sql script at macOs/linux. (#1935)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-24 16:42:20 +03:00
Ainurandnaumov 7acaf2668d CB-1392 add plain name for database nodes (#1937)
* CB-1392 add plain name for database nodes

* CB-1392 support plain name

* CB-1392 don't show file type for rm node

* CB-1392 deprecate get full name from nav node

* CB-1392 do not send plain name if it is the same as name

* CB-1392 move getting plain name logic to the function

* CB-1392 gql add comment for deprecated param

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
2023-08-24 16:40:11 +03:00
alexandEvgeniaBzzz 9839a8fc26 CB-3849 hide password value in main auth dialogs (#1924)
* CB-3849 hide password value in main auth dialogs

* CB-3849 add mergeRefs hook

* CB-3849 hide ssh password value in auth connection form

* CB-3849 allow empty string

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-24 16:08:57 +03:00
Dmitriy OsipovandDaria Marutkina fb6a3c4c69 CB-3732: fix table-error that prevent click on table (#1939)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-24 12:37:05 +03:00
Ainur daf3811b5c CB-3756 add datasource permission updated event (#1926)
* CB-3756 add datasource permission updated event

* CB-3756 use object type enums in rest controllers
2023-08-23 16:19:59 +03:00
Ainur d84fa05f58 Revert "CB-3810" (#1941) 2023-08-23 13:58:14 +02:00
alexandDaria Marutkina 2704db7bc9 CB-3865 add grouping for the provider properties (#1932)
* CB-3865 add grouping for the provider properties

* CB-3865 make fields large

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-23 12:56:36 +02:00
Dmitriy OsipovandEvgeniaBzzz 18c2d7bb02 CB-3762: fix inability to disable menu items (#1923)
* CB-3762: fix inability to disable menu items

* CB-3762 check that orderItems not added new actions

* CB-3762 fix order-items

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-23 11:29:30 +03:00
Dmitriy OsipovandDaria Marutkina f2239f596c CB-3606: fix active-query-extension update (#1933)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-23 11:28:56 +03:00
DenisSinelnikov 00611a0f26 Merge pull request #1922 from dbeaver/CB-3810-update-cache
CB-3810
2023-08-23 12:25:20 +04:00
alex fe71b00ba0 CB-3881 change tooltip (#1927) 2023-08-23 00:32:22 +02:00
alexandEvgeniaBzzz 20b94f06f6 CB-3782 add tooltip to the select container switch (#1936)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-23 00:32:04 +02:00
alexandEvgeniaBzzz cd4e97b4d9 CB-3806 change error place (#1928)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-23 00:31:33 +02:00
Daria Marutkina d4c7dd9676 Merge branch 'devel' into CB-3810-update-cache 2023-08-22 15:58:32 +02:00
Daria Marutkina fa6476e0d5 Merge pull request #1934 from dbeaver/dariamarutkina-patch-2
CB_2315 chore: update README
2023-08-21 14:23:49 +02:00
Daria Marutkina 32fcddf535 CB_2315 chore: update README 2023-08-21 14:22:54 +02:00
DenisSinelnikov 7682304a25 Merge branch 'devel' into CB-3810-update-cache 2023-08-21 14:16:22 +04:00
Alexey acdb139739 Fix/cb-3887-cb-3888/cherry-pick (#1931) 2023-08-18 16:55:05 +03:00
15cb96a68f CB-3814 respect ssl default values (#1910)
* CB-3814 respect ssl default values

* CB-3814 use utils fn to avoid null and undefined

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 22:44:21 +03:00
35668e69b4 CB-3452 NTLM (#1919)
* CB-3837 separate flag for federated providers

* CB-3452 feat: support configurable auth providers

* CB-3452 fix: auth tab switching

* CB-3452 fix: auth dialog credentials reset

* CB-3837 separate flag for federated providers

* CB-3452 feat: support configurable auth providers

* CB-3452 fix: auth tab switching

* CB-3452 fix: auth dialog credentials reset

* CB-3836 ntlm auth provider

* CB-3452 fix: provider configuration tab id

* CB-3836 fix ntlm flow

* CB-3452 chore: add Integer type mapping

---------

Co-authored-by: Aleksei Potsetsuev <wrouds@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-16 22:41:02 +03:00
AinurandEvgeniaBzzz aa1edf0e29 CB-3098 filter auth model properties fix (#1873)
* CB-3098 filter auth model properties fix

* CB-3098 do not fill session credentials in connection info

* CB-3098 default value fix

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 22:39:53 +03:00
Alexander SkoblikovandEvgeniaBzzz d6d99f5e9c CB-3866 check that user has projects (#1918)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 19:22:06 +03:00
AlexeyandDaria Marutkina f2896b8b90 CB-3879 fix: support redirects from index page (#1921)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-16 19:07:12 +03:00
30c4020790 Cb 3679 administration toolbar redesign (#1914)
* CB-3679 refactor tools panel to css-modules

* CB-3679 update administration toolbar styles

* CB-3679 update user-administration tabs styles

* CB-3679 fix menu-item styles

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 17:53:20 +03:00
Denis Sinelnikov 038f03823c CB-3810. Fixed display after add/update datasource for two or more (session/account) with same access datasources at the list of templates 2023-08-16 18:37:59 +04:00
5206680590 CB-3769-user-role-change-event (#1880)
* CB-3825 add role changed event

* CB-3825 dc use event controller for sending events to mq

* CB-3769 remove fields from gql subject event type

* CB-3821 support CbSubjectPermissionUpdateEvent

* CB-3769 session state job do not refresh permissions

* CB-3769 change locale

* CB-3769 use sm subject type

* CB-3821 fix event name type

* CB-3825 remove core-localization package

* CB-3824 change imports

* CB-3825 translate all messages

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Айнур Ягудин <ainur@MacBook-Air-Ajnur.local>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: Alexey <wrouds@gmail.com>
2023-08-16 15:19:31 +03:00
Serge Rider f736dd4b46 Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2023-08-16 13:40:54 +02:00
Serge Rider 11e320e225 23.1.5 version bump 2023-08-16 13:40:25 +02:00
439d2505cc CB-3741 automatically refresh token for websocket connection (#1900)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 13:46:36 +03:00
AinurandEvgeniaBzzz 5f3405f7bf CB-3872 ssh key init connection fix (#1917)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-16 13:46:08 +03:00
AlexeyandDaria Marutkina 11507c362d CB-895 feat: columns rearrangement (#1903)
* CB-895 feat: columns rearrangement

* CB-895 chore: remove unused vars

* CB-895 chore: pr review fixed

* CB-895 fix: rearranged columns size calculation

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-16 12:17:22 +03:00
31dd99c573 CB-3503 generate different token for the safari (#1909)
* CB-3503 generate different token for the safari

* CB-3503 change ssh autocomplete safari

* CB-3503 add autofill token to ssl safari

---------

Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-08-16 12:16:52 +03:00
AlexeyandEvgeniaBzzz 9443351204 CB-3868 fix: page aliases (#1911)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-15 21:04:12 +03:00
Serge Rider 79050cddcf 23.1.5 version bump 2023-08-15 18:13:23 +02:00
Alexander SkoblikovandDaria Marutkina 4e6119d835 CB-3676 handle file modification exceptions (#1899)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-15 18:27:24 +03:00
Alexey a4de35c8c6 CB-3870 fix(build): use proper env in babel config (#1916) 2023-08-15 12:50:26 +03:00
Dmitriy Osipov 07f8fb6081 fix styles for element size css module (#1915) 2023-08-15 12:03:14 +03:00
Dmitriy Osipov 77b2601523 CB-3382 fix locales (#1912) 2023-08-15 01:20:13 +03:00
Alexey 3983595b5f fix(build): dependencies (#1913) 2023-08-15 01:18:18 +03:00
Dmitriy Osipov d6febf4c48 chore: add react-refresh-plugin for better dev experience" (#1874)
* chore: add react-refresh-plugin for better dev experience"

* chore: move plugin to babel.config.js

* fix tests for react-refresh
2023-08-15 00:03:27 +03:00
Alexey f771757f11 CB-3848 fix: users provisioning (#1906) 2023-08-14 23:54:36 +03:00
Alexander SkoblikovandDaria Marutkina d01d862e3e CB-3812 git improvements (#1892)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-14 22:17:28 +03:00
451a866149 CB-3382 api for other grouping panel functions (#1870)
* CB-3382 api for other grouping panel functions

* CB-3382 add show duplicates only param

* CB-3382 gql schema fix

* CB 3382 add grouping configuration form

* CB-3382 fix problems

* CB-3382: fix problems

* CB-3382 add state for show duplicates btn

* CB-3382 fix selectors specificity

* CB-3382 fix locales

* CB-3382 fix locales

---------

Co-authored-by: Dmitry Osipov <teunlao@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-14 22:15:55 +03:00
Alexey 1a06b4e17b fix(build): assets priority (#1905) 2023-08-14 13:21:45 +03:00
Alexey c55ad1bac9 dev: update dev commands (#1904) 2023-08-14 12:28:10 +03:00
Alexey 3aa9b80e56 Build/cb-3820/generate-gql-types-on-build (#1894)
* CB-3820 chore: remove gql sdk.ts

* CB-3820 chore: build gql types before build

* CB-3820 fix: generate types before running tests

* CB-3820 chore: update github actions

* CB-3820 chore: update github actions

* CB-3820 chore: update github actions add cache

* CB-3820 chore: update github actions add cache

* CB-3820 chore: update github actions add cache

* CB-3820 chore: update github actions add cache
2023-08-11 23:49:41 +03:00
AlexeyandDaria Marutkina 617f3b45d7 CB-596 feat: pagination for database objects (#1891)
* CB-596 feat: pagination for database objects

* CB-596 chore: review fixes

* CB-596 fix: loading users

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-11 14:28:21 +03:00
AinurandDaria Marutkina af67b02d9e CB-3702 add remove project in same session fix (#1872)
* CB-3702 add remove project in same session fix

* CB-3702 gql add delete project fix

* CB-3702 remove unused function

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-10 21:52:12 +03:00
Dmitriy OsipovandEvgeniaBzzz 4f4c637866 CB-3655 disable save button when name not changed (#1895)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-10 19:12:16 +03:00
Dmitriy Osipov 5433262127 CB-3743 chore: update yarn lock (#1898) 2023-08-10 16:23:12 +03:00
Alexey 7b5855e5b8 CB-2329 chore: update tasks (#1897) 2023-08-10 15:09:09 +03:00
alexandEvgeniaBzzz 79080444fd CB-3758 reorganize connection management tab (#1890)
* CB-3758 reorganize connection management tab

* CB-3758 remove template checkbox from template form

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-10 14:10:03 +03:00
AlexeyandDaria Marutkina 044cafae24 CB-3724 feat: move user provisioning to users administration (#1871)
* CB-3724 feat: move user provisioning to users administration

* CB-3724 fix: display information that authentication method is disabled

* CB-3724 fix: auth dialog styles

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-10 01:35:08 +03:00
Dmitriy OsipovandEvgeniaBzzz 8c51b22d81 CB-3799: fix button label centering (#1893)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-09 18:55:17 +03:00
Dmitriy OsipovandEvgeniaBzzz 1ef7a4570d CB-3743 keep fonts locally (#1888)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-09 18:54:56 +03:00
Serge Rider 40569b708a Merge branch 'devel' of https://github.com/dbeaver/cloudbeaver into devel 2023-08-09 15:53:59 +02:00
Serge Rider 8e67a473d1 #1857 NPE fix 2023-08-09 15:53:42 +02:00
Alexander SkoblikovandDaria Marutkina 5df9b187b4 CB-3712 okta provisioning (#1879)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-09 14:38:49 +03:00
Ainur 17a7e0c39d CB-3599 multiple results fix (#1876) 2023-08-08 21:13:14 +03:00
dependabot[bot] 292acd5d51 Chore(deps): bump com.h2database:h2 in /apps/h2-query-executor (#1885)
Bumps [com.h2database:h2](https://github.com/h2database/h2database) from 1.4.199 to 2.2.220.
- [Release notes](https://github.com/h2database/h2database/releases)
- [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.2.220)

---
updated-dependencies:
- dependency-name: com.h2database:h2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-08 13:29:47 +03:00
Serge Rider 421549c08a CB-3828 Replace H2 v dependency with patched legacy jar (#1884) 2023-08-08 13:24:44 +03:00
EvgeniaBzzz e9b6f6e888 Merge pull request #1883 from dbeaver/EvgeniaBzzz-patch-2
Update README.md
2023-08-08 13:16:33 +03:00
EvgeniaBzzz b205876ff4 Update README.md 2023-08-08 13:15:23 +03:00
AinurandEvgeniaBzzz 028b04b3b2 CB-3635 update firebird driver (#1867)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-08 12:13:48 +03:00
alexandEvgeniaBzzz 32624147f8 CB-3632 do not preload connections if session update is in progress (#1869)
* CB-3632 do not preload connections if session update is in progress

* CB-3632 add comments

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-08 02:08:17 +03:00
EvgeniaBzzz 0d11f60a58 Merge pull request #1877 from dbeaver/EvgeniaBzzz-patch-1
CB_2314 chore: update README
2023-08-07 15:54:19 +03:00
EvgeniaBzzz f3bc8a28ec CB_2314 chore: update README 2023-08-07 15:52:02 +03:00
serge-rider 623f4458d9 23.1.4 config 2023-08-02 22:02:35 +02:00
alex eaeec9f1be CB-3628 clean key errors in ResourceError on refresh (#1868) 2023-08-02 21:27:38 +03:00
AinurandDaria Marutkina dd501d0716 CB-2903 apply predefined access to data sources from config file (#1833)
* CB-2903 apply predefined access to data sources from config file

* CB-2903 get subjects from auth subject table

* CB-2903 filtered subjects fix

* CB-2903 use json instead of conf for permissions configuration

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-02 19:11:59 +03:00
alex 1d2e1cd823 CB-3656 add validation inside the save script dialog (#1847)
* CB-3656 add validation inside the save script dialog

* CB-3656 respect root folder
2023-08-02 17:35:23 +03:00
Ainur b73dbe684b CB-3539 script task fix for TM (#1851) 2023-08-02 15:58:33 +03:00
AinurandEvgeniaBzzz 9b3098d68f CB-3448 anonymous user get query history from session id (#1845)
* CB-3448 anonymous user get query history from session id

* CB-3448 notify session change in anonymous user auth

---------

Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-08-02 13:59:24 +03:00
Ainur 069218cb5e CB-2403 add icon for reverse proxy (#1864) 2023-08-02 13:48:07 +03:00
AinurandDaria Marutkina 29ec2e09b7 CB-3744 add name service handler (#1862)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-02 13:47:17 +03:00
5b077f3189 Cb 3667 navigator filters (#1863)
* CB-3667 Navigator filters model

* CB-3667 Navigator filters model + implementation

* CB-3667 Instructions

* CB-3668 add navigator filters plugin

* CB-3667 Input parameters fix

* CB-3668 add include & exclude tables

* CB-3667 Save filter settings

* CB-3667 register plugin

* CB-3667 Load filter settings

* CB-3668 rename plugin

* CB-3668 add css modules

* CB-3668 add dependencies

* CB-3668 review fixes

* CB-3668 hide delete button by default

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-08-01 17:00:31 +03:00
Dmitriy Osipov 73b5e8fc59 CB-3780 fix: group component classes order (#1866) 2023-07-31 18:35:35 +03:00
Dmitriy Osipovandmr-anton-t 1073335af5 CB-3586: migrate tags to css-modules (#1835)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-31 18:35:16 +03:00
Alexander SkoblikovandDaria Marutkina d5cdb8fb43 CB-3385 add first/lastname to rp auth (#1857)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-31 15:01:35 +03:00
Alexander SkoblikovandDaria Marutkina 752f913db0 CB-2580 aws open id provider (#1861)
* CB-2580 aws open id provider

* CB-2580 read team meta in getUserTeams

---------

Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-31 15:01:02 +03:00
0d665a6b7b CB-3727: load common fields of network handler by default (#1854)
Co-authored-by: Alexey <wrouds@gmail.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-28 16:42:09 +03:00
Dmitriy OsipovandEvgeniaBzzz 84cbf143ae CB-3672 fix: possibility to remove and rename project in RM (#1859)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-28 14:01:34 +03:00
Alexey f4a62bbca8 chore: configure graphql codegen & types (#1860) 2023-07-28 13:59:12 +03:00
Alexander Skoblikovandmr-anton-t d93d7748cf Cb 3738 exception when logout invalid update token (#1853)
* CB-3738 log all gql errors

* CB-3310 do not update token for child sessions

* CB-3738 skip headless session on refresh

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-28 13:20:47 +03:00
Dmitriy OsipovandEvgeniaBzzz d2f1f29e80 CB-3746 fix: merge view separator line color (#1855)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-28 00:59:05 +03:00
AinurandDaria Marutkina b7add23754 CB-3686 remove rm resource path from events (#1824)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-27 18:17:25 +03:00
07fc1f88b7 CB-3616 add logs for local rm (#1839)
* CB-3616 add logs for local rm

* CB-3616 add info about project id in logs

---------

Co-authored-by: Serge Rider <serge@jkiss.org>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-27 18:16:37 +03:00
Ainur c79a9a8efa CB-3775 test ssh handler fix (#1852) 2023-07-27 18:15:37 +03:00
e785d98c9b CB-3731 update trino driver (#1841)
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-27 18:14:25 +03:00
Tatiana Fokinaandmr-anton-t 45c201c465 Cb 3587 migrate snackbars to css modules (#1842)
* CB-3587 add css modules, remove reshadow styles from snackbars

* CB-3587 fix notification cross button style

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-27 17:34:39 +03:00
664864d478 CB-3640 gitignore settings (#1830)
* CB-3640 gitignore settings

* CB-3640 ignore backup files

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-27 16:46:44 +03:00
3cdcb07646 CB-3268 feat: admin users pagination (#1821)
* CB-3268 feat: admin users pagination

* CB-3268 fix: code style

* CB-3268 feat: filter users by enabled state

* CB-3268 feat: limit users loading

* CB-3268 fix: use limit/offset pagination

* CB-3268 fix pagination api

* CB-3268 fix users query

* CB-3268 fix: users refresh

---------

Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-27 15:27:14 +03:00
Tatiana Fokinaandmr-anton-t e33eb9fd60 Cb 3584 migrate containers to css modules (#1834)
* CB-3584 migrate containers, migrate form controls to css modules

* CB-3584 remove old container styles, fix layout props, fix styles

* CB-3584: Fix properties table filter style

* CB-3584 fix styles

* CB-3584 fix styles

* CB-3584 fix sizing styles

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-27 13:24:47 +03:00
Alexey 8fba6107b2 CB-3740 fix: handle authentication errors (#1844)
* CB-3740 fix: handle authentication errors

* CB-3740 chore: add localization
2023-07-26 20:13:44 +03:00
Alexey f41effd655 chore: deprecate useController (#1850) 2023-07-26 18:48:03 +03:00
mayer 9b34a496dc dbeaver/dbeaver-devops#635 non root images (#1848)
* devops#635 openshift support

* devops#635 openshift support: subdir name append
2023-07-26 15:17:16 +03:00
Dmitriy OsipovandEvgeniaBzzz 93c9cdd23d CB-3684 rename options in connection menu (#1836)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-26 14:34:52 +03:00
Dmitriy OsipovandEvgeniaBzzz c7e6cf9d95 CB-3476 feat: save text selection and cursor position for each tab (#1846)
Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
2023-07-26 13:38:30 +03:00
Serge Rider 27b0180107 dbeaver/pro#1797 Eliminate redundant i18n files (#1843) 2023-07-25 14:52:50 +03:00
f073954a32 Cb 1768 ssl support (#1829)
* CB-1768 filter desktop network handlers

* CB-3692 add ssl tab

* CB-3692 use secure properties for the ssl

* CB-1768 save ssl credentials fix

* CB-1768 set secure properties fix

* CB-1768 set secure properties fix

* CB-3692 add  properties categories

* CB-1768 add password feature

* CB-3692 support ssl in auth form

* CB-1768 do not mutate proxy objects

* CB-3692 do not pass secure properties if there is no changes

* CB-3692 do not send secure properties for the ssh

* CB-3692 add comments

* CB-3692 disable autofill

* CB-3692 disable autofill on init connection

* CB-3692 convert observables to non observables

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-24 17:49:16 +03:00
Dmitriy OsipovandAlexey e5ed5c8682 CB-3585 migrate itemList to css-modules (#1832)
Co-authored-by: Alexey <wrouds@gmail.com>
2023-07-24 16:37:19 +03:00
Daria Marutkina 90cd350267 Merge pull request #1840 from dbeaver/dariamarutkina-patch-1
CB_2313 chore: update README
2023-07-24 12:52:43 +02:00
Daria Marutkina 1360631ab4 CB_2313 chore: update README 2023-07-24 12:52:17 +02:00
dda35760eb CB-3612 provisioning api (#1804)
* CB-3612 provisioning api

* CB-3612 review fixes

* CB-3486 rename getters

* CB-3486 azure ad get users info

* CB-3612 add filter to gql

* CB-3612 get resource token only after calling gql func

* CB-3486 fix front errors

* CB-3486 add translation

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: Tatiana Fokina <tatiana.fokina@dbeaver.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-19 20:30:58 +03:00
1086151bcb CB-1652 add cross button to search fields (#1803)
* CB-1652 add cross button to search fields

* СB-1652 PR fixes

* CB-1652 PR fixes

* CB-1652 add cross button to driver properties filter

* CB-1652 fix typo

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-19 18:58:21 +03:00
Dmitry Osipovandmr-anton-t e7c066e592 CB-3720 fix: changed extensions order for editor (#1825)
* CB-3720 fix: changed extensions order for editor

* CB-3720 add priority for extensions

---------

Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-19 17:33:24 +03:00
Dmitry Osipovandmr-anton-t 5aae41d1fe CB-3725: fix: prop name for MenuBarSmallItem (#1828)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-19 15:32:53 +03:00
Dmitry Osipovandmr-anton-t 4ad921a9c8 CB-3721 fix: replaced MOD key with CTRL in Linux (#1826)
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-19 14:40:04 +03:00
632c93f246 CB-3519 ability-to-unlink-sso-credentials-from-user (#1822)
* CB-3670 delete user credentials api

* CB-3669 add ability to remove user creds

* CB-3669 use modules

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
Co-authored-by: Daria Marutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-19 12:26:22 +03:00
Alexey 4e4b817a38 chore: update eclipse configs (#1827) 2023-07-19 12:07:20 +03:00
Serge Rider b097b1147a Extra Java opens 2023-07-18 17:56:32 +02:00
Serge Rider d00f08b9d0 23.1.3 config 2023-07-18 14:42:51 +02:00
Serge Rider 9d0ecce84f 23.1.3 config 2023-07-18 14:41:55 +02:00
7550915e9c CB-3544 clarify logs (#1820)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
Co-authored-by: mr-anton-t <42037741+mr-anton-t@users.noreply.github.com>
2023-07-18 14:34:33 +03:00
Alexeyanddariamarutkina 78c19187de Feat CB-3030 conflict resolving (#1814)
* CB-3030 feat: conflict resolving

* CB-3030 fix: display os specific key instead of mod

* CB-3030 fix: sql editor status

* CB-3030 fix: styles and data validation

* CB-3030 fix: sql editor styles

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-17 22:10:15 +03:00
Alexeyanddariamarutkina fc592908c2 CB-3680 fix: add suspense loader (#1823)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-16 20:31:43 +03:00
alexanddariamarutkina ba0cd2d3fa CB-3600 support files aggregation (#1813)
* CB-3600 support files aggregation

* CB-3600 notify about duplicates

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-14 15:15:34 +03:00
alexanddariamarutkina 872c226522 Cb 3675 projects notifications (#1818)
* CB-3675 add project notifications

* CB-3675 revert status message logic

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-14 15:15:04 +03:00
Alexeyanddariamarutkina ab94dd837b CB-3641 fix: search in visible node name (#1815)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-12 12:43:47 +03:00
alexandAlexey dce23485a7 CB-3549 fill connection config with defaults (#1806)
* CB-3549 fill connection config with defaults

* CB-3549 move mode check outside of the update name fn

---------

Co-authored-by: Alexey <wrouds@gmail.com>
2023-07-11 14:19:11 +03:00
Tatiana Fokinaanddariamarutkina 17510f2de1 CB-3608 memoize parse script (#1805)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-10 14:55:24 +03:00
Serge Rider 98d171e503 dbeaver/pro#1766 legacy krb5 support (#1807)
* dbeaver/pro#1766 Legacy krb5 support

* 23.1.2 version bump
2023-07-10 11:19:26 +03:00
dariamarutkina 736d91fbe3 Merge pull request #1812 from dbeaver/dariamarutkina-patch-1
CB_2312 chore: update README
2023-07-10 10:00:47 +02:00
dariamarutkina c0b71a431a CB_2312 chore: update README 2023-07-10 10:00:12 +02:00
d8585e6a37 CB-3654 fix: remove file extension from save notification (#1799)
* CB-3654 fix: remove file extension from save notification

* CB-3654 fix error message on saving rm resource

---------

Co-authored-by: Ainur <yagudin10@yandex.ru>
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-05 21:34:41 +04:00
Serge Rider 6668197625 23.1.2 version bump 2023-07-05 13:56:25 +02:00
Alexey b3f6eb929b chore: use prettier to format sdk files (#1801) 2023-07-05 14:19:05 +04:00
Alexey 9f885eac34 chore: prettier project (#1800) 2023-07-05 14:05:39 +04:00
Alexey 5945bc1823 fix: remove admin settings (#1798) 2023-07-05 13:40:47 +04:00
Ainur e6d3b2af7f CB-3576 data receiver return dative database results (#1794)
* CB-3576 return string for array data kind

* CB-3576 add comment
2023-07-05 12:18:32 +03:00
Alexander Skoblikovandnaumov 0c981a67f4 CB-3516 add compress flag to the export settings (#1792)
* CB-3516 add compress flag to the export settings

* CB-3516 add compression checkbox

* CB-3516 zip export result download fix

* CB-3516 fix zip name

---------

Co-authored-by: naumov <iamemptyhuh@gmail.com>
2023-07-05 12:17:42 +03:00
Tatiana Fokinaanddariamarutkina a571eeef8e CB-3615 change notification for app update, remove dialog (#1796)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-07-05 12:44:35 +04:00
alexandAleksandr Skoblikov 3642bbfa41 CB-3451 git integration (#1782)
* CB-3570 add manual save

* CB-3451 git settings api

* CB-3451 migrate to the new config model

* CB-3451 improve locks, update gql

* CB-3451 fix RM configuration

* CB-3570 resolve conflicts

* CB-3451 checkout remote branch

* CB-3451 review fix

* CB-3451 improve logs/fix private project access

* CB-3570 review fixes

* CB-3570 remove hasChanges flag

* CB-3570 debounce saveProperties

---------

Co-authored-by: Aleksandr Skoblikov <aleksandr.skoblikov@dbeaver.com>
2023-07-04 21:35:38 +03:00
Tatiana Fokinaanddariamarutkina ba48b282fd Cb 3536 add settings panel (#1787)
* CB-3536 add settings panel

* CB-3536 filter settings by group

* CB-3536 PR fixes, add settings to panel

* CB-3536 export settings group

* CB-3536 add translations, fix indentation

* CB-3536 refactor translations

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-06-30 15:22:20 +04:00
Alexey a8e8f7ef33 CB-3589 feat: sync connection containers with nav-tree (#1788) 2023-06-29 18:57:27 +04:00
Ainur 7af7fafb42 CB-3498 get navigator model from project (#1779) 2023-06-29 14:41:05 +03:00
alexanddariamarutkina 9b43e2f158 CB-3595 remove scroll behaviour (#1791)
Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-06-28 22:49:29 +02:00
Elizabeth c78adb94a2 dbeaver/pro#1641 Add cb_workspace_configuration event to the default event handler (#1774) 2023-06-28 17:53:22 +03:00
Alexeyanddariamarutkina 8292eb3ac9 CB-3517 styling (#1768)
* feat: CB-3517 css-modules for styling components

* CB-3517 refactor: use new styles system for Menu

* CB-3517 refactor: new styling system

* CB-3517 fix: log viewer styles

* CB-3517 chore: remove extra styles

* CB-3517 fix: context menu offset

* CB-3517 chore: review code cleanup

* CB-3517 chore: revert some changes

* CB-3517 chore: revert some changes

* CB-3517 chore: revert some changes

* CB-3517 fix: tabs padding

* CB-3517 fix: tab and checkbox styles

* CB-3517 chore: increase result tabs in sql editor

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-06-27 19:57:01 +04:00
Alexey 10a3dcc1e5 CB-3637 chore: update security policy (#1790) 2023-06-27 18:15:50 +04:00
Alexey 796afa3d17 chore: fix yarn.lock (#1789) 2023-06-27 13:55:41 +04:00
Alexeyanddariamarutkina d4739a0dba Feat CB-3293 node info transformer (#1778)
* CB-3293 feat: node info transformer

* CB-3293 feat: hide resource extension in nav-tree

* CB-3293 feat: rename resources without extension

* CB-3293 fix: resource folder renaming

* CB-3293 fix: add resource delete confirmation

* CB-3293 chore: remove unused code

* CB-3293 fix: resource deletion

* CB-2393 chore: unify delete confirmation dialog

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-06-27 13:46:55 +04:00
dariamarutkina 65718f681c Merge pull request #1785 from dbeaver/dariamarutkina-patch-7
CB_2311 chore: update README
2023-06-26 11:29:11 +02:00
dariamarutkina 32b38d9732 CB_2311 chore: update README 2023-06-26 11:28:52 +02:00
Alexey d9e6dcfd02 CB-3365 doc: add jsdoc to resources (#1783)
* CB-3365 doc: add jsdoc to resources

* CB-3365 fix: rename clearData -> resetDataToDefault

* CB-3365 fix: grammar
2023-06-26 12:21:15 +04:00
AinurandAlexander Skoblikov cd10ed2ea1 Cb 3470 hotfix (#1780)
* CB-3470 fix sql query for auth subject

* CB-3470 fix sql query for auth subject (#1776)

* CB-3470 sql query fix

---------

Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
2023-06-22 16:23:13 +03:00
Ainur f3b9034855 CB-3470 fix sql query for auth subject (#1775) 2023-06-22 13:08:45 +03:00
1933 changed files with 48531 additions and 33439 deletions
+76
View File
@@ -0,0 +1,76 @@
name: frontend-cache
on:
push:
branches: ["devel"]
paths:
- "webapp/**"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build_and_test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./webapp
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: restore yarn cache
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: restore node_modules
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: restore typescript cache
uses: actions/cache@v3
with:
path: "**/packages/*/dist"
key: ${{ runner.os }}-dist-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-dist-
- name: yarn install
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: install
- name: yarn lerna bootstrap
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna bootstrap
- name: build
uses: borales/actions-yarn@v4
with:
dir: webapp/packages/product-default
cmd: build # build tyescript source code
- name: test
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna run test # build packages that have test script
+29
View File
@@ -0,0 +1,29 @@
name: cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
+80
View File
@@ -0,0 +1,80 @@
name: frontend
on:
# Triggers the workflow on push or pull request events but only for the "devel" branch
pull_request:
branches: ["devel"]
paths:
- "webapp/**" # monitor for the frontend changes
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Allows you to reuse workflows by referencing their YAML files
workflow_call:
jobs:
build_and_test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./webapp
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
- name: restore yarn cache
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: restore node_modules
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node_modules-
- name: restore typescript cache
uses: actions/cache@v3
with:
path: "**/packages/*/dist"
key: ${{ runner.os }}-dist-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-dist-
- name: yarn install
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: install
- name: yarn lerna bootstrap
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna bootstrap
- name: build
uses: borales/actions-yarn@v4
with:
dir: webapp/packages/product-default
cmd: bundle
- name: test
uses: borales/actions-yarn@v4
with:
dir: webapp
cmd: lerna run test
-32
View File
@@ -1,32 +0,0 @@
name: Run Jest Tests
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "devel" branch
pull_request:
branches: [ "devel" ]
paths:
- 'webapp/**' # monitor for the frontend changes
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
run-jest-tests:
# The type of runner that the job will run on
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./webapp
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm install yarn -g
- run: yarn
- run: yarn lerna bootstrap
- run: yarn lerna run test
@@ -1,4 +1,4 @@
name: "Commit Message Validation"
name: validation
on:
pull_request:
@@ -11,7 +11,7 @@ on:
- edited
- ready_for_review
- labeled
jobs:
validate-commit-message:
uses: dbeaver/dbeaver/.github/workflows/reused-commit-msgs-validator.yml@devel
commit-message:
uses: dbeaver/dbeaver/.github/workflows/reused-commit-msgs-validator.yml@devel
+2 -1
View File
@@ -19,6 +19,7 @@
"VisualStudioExptTeam.vscodeintellicode",
"yzhang.markdown-all-in-one",
"GraphQL.vscode-graphql-syntax",
"mrmlnc.vscode-json5"
"mrmlnc.vscode-json5",
"esbenp.prettier-vscode"
]
}
+22 -9
View File
@@ -4,9 +4,19 @@
{
"type": "chrome",
"request": "launch",
"name": "Debug CE",
"name": "Chrome",
"url": "http://127.0.0.1:3100",
"webRoot": "${workspaceFolder}/webapp/packages/product-default"
"webRoot": "${workspaceFolder}/..",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///*": "${workspaceFolder}/../*"
},
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**",
"${workspaceFolder}/webapp/**/node_modules/**/*.js",
"${workspaceFolder}/webapp/**/dist/**/*.js"
]
},
{
"type": "java",
@@ -14,21 +24,21 @@
"cwd": "${workspaceFolder}/../opt/cbce",
"request": "launch",
"mainClass": "org.eclipse.equinox.launcher.Main",
"classPaths": [
"${env:DBEAVER_DEVEL_ECLIPSE_PATH}/plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar"
],
"windows": {
"type": "java",
"name": "CloudBeaver CE",
"request": "launch",
"mainClass": "org.eclipse.equinox.launcher.Main",
"classPaths": [
"${workspaceFolder}/../eclipse/eclipse/plugins/org.eclipse.equinox.launcher_1.6.500.v20230717-2134.jar"
],
"args": [
"-product",
"io.cloudbeaver.product.ce.product",
"-configuration",
"file:${env:DBEAVER_DEVEL_ECLIPSE_WORKSPACE_PATH}/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/",
"file:${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/",
"-dev",
"file:${env:DBEAVER_DEVEL_ECLIPSE_WORKSPACE_PATH}/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/dev.properties",
"file:${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/dev.properties",
"-os",
"win32",
"-ws",
@@ -54,13 +64,16 @@
"name": "CloudBeaver CE",
"request": "launch",
"mainClass": "org.eclipse.equinox.launcher.Main",
"classPaths": [
"${workspaceFolder}/../eclipse/Eclipse.app/Contents/Eclipse/plugins/org.eclipse.equinox.launcher_1.6.500.v20230717-2134.jar"
],
"args": [
"-product",
"io.cloudbeaver.product.ce.product",
"-configuration",
"file:${env:DBEAVER_DEVEL_ECLIPSE_WORKSPACE_PATH}/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/",
"file:${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/",
"-dev",
"file:${env:DBEAVER_DEVEL_ECLIPSE_WORKSPACE_PATH}/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/dev.properties",
"file:${workspaceFolder}/../eclipse/workspace/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product/dev.properties",
"-os",
"macosx",
"-ws",
+2 -1
View File
@@ -1,6 +1,7 @@
{
"editor.tabSize": 2,
"editor.formatOnSave": true,
"editor.linkedEditing": true,
"task.autoDetect": "off",
@@ -8,6 +9,7 @@
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx16G -Xms100m -Xlog:disable",
"java.compile.nullAnalysis.mode": "automatic",
"typescript.preferences.useAliasesForRenames": false,
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.preferences.includePackageJsonAutoImports": "on",
"typescript.preferences.quoteStyle": "single",
@@ -20,7 +22,6 @@
"typescript",
"typescriptreact"
],
"eslint.packageManager": "yarn",
"eslint.workingDirectories": ["webapp"],
"editor.defaultFormatter": "esbenp.prettier-vscode",
+14 -37
View File
@@ -13,21 +13,7 @@
},
"tasks": [
{
"label": "Generate dev proprties for CBCE",
"type": "shell",
"command": "mvn",
"args": [
"package",
"-q",
"exec:java",
"-Dexec.args=-productFile ${workspaceFolder}/server/product/web-server/CloudbeaverServer.product -projectsFolder ${workspaceFolder}/../ -eclipse ${env:DBEAVER_DEVEL_ECLIPSE_PATH} -output ${env:DBEAVER_DEVEL_ECLIPSE_WORKSPACE_PATH}/.metadata/.plugins/org.eclipse.pde.core/CloudbeaverServer.product"
],
"options": {
"cwd": "${workspaceFolder}/../dbeaver-packaging/tools/eclipse-plugins-resolver"
}
},
{
"label": "Run Tests",
"label": "Run Tests CE",
"type": "shell",
"command": "yarn",
"group": "test",
@@ -35,25 +21,27 @@
},
{
"label": "Run DevServer CE",
"group": "build",
"isBackground": true,
"type": "shell",
"command": "yarn",
"args": [
"dev",
"--",
"--env",
"server=${input:stage.ce}",
"--host",
"0.0.0.0"
],
"isBackground": true,
"args": ["dev"],
"options": {
"env": {
"server": "${input:stage.ce}"
},
"cwd": "${workspaceFolder}/webapp/packages/product-default"
}
},
{
"label": "Build CE",
"type": "shell",
"command": "./build-sqlite.bat",
"windows": {
"command": "./build-sqlite.bat"
},
"osx": {
"command": "./build-sqlite.sh"
},
"options": {
"cwd": "${workspaceFolder}/deploy"
},
@@ -65,19 +53,8 @@
{
"label": "Yarn Install",
"type": "shell",
"command": "yarn",
"command": "yarn install; yarn lerna bootstrap",
"args": []
},
{
"label": "Lerna Bootstrap",
"type": "shell",
"command": "yarn",
"args": ["lerna", "bootstrap"]
},
{
"label": "Bootstrap",
"dependsOrder": "sequence",
"dependsOn": ["Yarn Install", "Lerna Bootstrap"]
}
],
"inputs": [
+47 -17
View File
@@ -22,27 +22,57 @@ You can see live demo of CloudBeaver here: https://demo.cloudbeaver.io
## Changelog
### CloudBeaver 23.1.0 - 2023-06-05
### CloudBeaver 23.2.3 - 2023-10-23
Changes since 23.0.0
- The SSL option is available for establishing a connection in SQL Server;
- Added the ability to edit binary values in a table;
- Different bug fixes and enhancements have been made.
- Data viewer:
- New grouping panel menu was added in the Data Viewer. This panel extracts unique values from the database column for count. Users can drag and drop the column to the grouping panel and get the results immediately. Sorting, filtering and exporting of the results are available on the Grouping panel.
### CloudBeaver 23.2.2 - 2023-10-09
- The 'Save credentials' checkbox has been removed from a template creating form as credentials are not stored in templates;
- Different bug fixes and enhancements have been made.
### CloudBeaver 23.2.1 - 2023-09-25
- The Output tab has been implemented, which includes warnings, info and notices generated by the database when executing user queries;
- Scrollbars have been made theme-independent, resolving interface issues with light theme;
- Fixed an issue in the SQL editor where it was not possible to switch the active schema when working with Oracle databases;
- Different bug fixes and enhancements have been made.
23.2.0 - 2023-09-04
- Performance:
- Pagination has been added to the Navigation tree and metadata viewer, allowing working with more than 1000 database items;
- Access Management:
- Access permissions can be specified for pre-configured connections via the configuration file;
- Reverse Proxy authentication now includes the option to provide users' First name and Last name;
- Authorization:
- The SSL option is now available for establishing connections in MySQL, PostgreSQL, Clickhouse;
- Connections:
- Connections are consistently displayed now when they are pre-configured into the workspace in the Global Configuration json file
- Navigation tree:
- The filters for the Navigation tree now allow hiding and showing schemas within the interface.
- The search request considers file names and excludes the .sql file extension for now;
- Data Editor:
- The ability to rearrange columns in the Data Editor has been added;
- The ability to use custom functions in the Grouping panel has been added;
- Administration:
- New Settings panel displays the product configuration settings such as Minimum fetch size, Maximum fetch size, and Default fetch size from the Data Editor;
- "Connection Management" tab has been renamed to "Connection Templates" - now only connection templates are displayed;
- SQL Editor:
- We improved the performance of the SQL-editor - as a result, handling scripts with up to 10 000 lines does not present any challenges;
- In the SQL-editor, pressing Tab/Space followed by Enter now causes the cursor to move to a new line;
- In the SQL editor, when the cursor goes back on the query, the previous hints are displayed;
- Error when running SQL with semicolon has been fixed.
- Connections:
- If there is an error in saving the data, the tab for the chosen connection dialog will stay open to allow corrections;
- The URL-configuration for PostgreSQL now correctly displays only a single database.
- Users can simultaneously edit resources for now, allowing them to work together;
- Support for displaying tables with nested arrays of objects has been added;
- The ability to compress export files allowed to increase in download speed, especially for larger files;
- UX in the search bar has been improved - users can delete a query or request by clicking on the cross icon;
- Driver management:
- The CE version now offers the updated sqlite-jdbc driver, version 3.41.2;
- CloudBeaver has the option to connect to H2 database version 2;
- The internal CloudBeaver database is upgraded to the newest H2 version 2 to avoid vulnerability issues. The database will be safely upgraded automatically for the servers with default configurations. You can perform this upgrade manually if you have a custom configuration for this database in your infrastructure.
- Connections:
- Option to increase the maximum size of text files displayed in the value panel (using the sqlTextPreviewMaxLength parameter) has been added;
- Support for custom logging configuration has been added. An external configuration file can be used instead of the default configuration.
- Custom settings have been added to the interface for the following dialogue connections: SQLite, DB2, SQL Server, MySQL, Oracle and PostgreSQL;
- Trino driver has been updated;
- Security:
- Password autofill functionality was removed;
- The "eye" icon for password fields has been removed - the passwords entered into fields will not be displayed in the interface for now;
- Many small bug fixes, enhancements, and improvements have been made
### Old CloudBeaver releases
+6 -6
View File
@@ -5,13 +5,13 @@
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------|
| 21.x | yes |
| 22.0 | yes |
| Version | Supported |
| ------- | --------- |
| 22.x | yes |
| 23.x | yes |
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities to devops@dbeaver.com.
You will receive a response from us within 48 hours.
Please report (suspected) security vulnerabilities to devops@dbeaver.com.
You will receive a response from us within 48 hours.
If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days.
+1 -1
View File
@@ -17,7 +17,7 @@
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<version>2.2.220</version>
</dependency>
</dependencies>
<build>
@@ -6,6 +6,8 @@
contentRoot: "web",
driversLocation: "drivers",
sslConfigurationPath:"${CLOUDBEAVER_SSL_CONF_PATH:workspace/.data/ssl-config.xml}",
rootURI: "/",
serviceURI: "/api/",
Regular → Executable
View File
+1 -1
View File
@@ -57,7 +57,7 @@ cd ..\cloudbeaver\webapp
call yarn
call yarn lerna bootstrap
call yarn lerna run build --no-bail --stream --scope=@cloudbeaver/product-default &::-- -- --env source-map
call yarn lerna run bundle --no-bail --stream --scope=@cloudbeaver/product-default &::-- -- --env source-map
cd ..\deploy
+1 -1
View File
@@ -57,7 +57,7 @@ cd ../cloudbeaver/webapp
yarn
yarn lerna run bootstrap
yarn lerna run build --no-bail --stream --scope=@cloudbeaver/product-default #-- -- --env source-map
yarn lerna run bundle --no-bail --stream --scope=@cloudbeaver/product-default #-- -- --env source-map
if [[ "$?" -ne 0 ]] ; then
echo 'Application build failed'; exit $rc
fi
+1 -1
View File
@@ -3,6 +3,6 @@ FROM eclipse-temurin:17.0.4.1_1-jre-focal
COPY cloudbeaver /opt/cloudbeaver
EXPOSE 8978
RUN find /opt/cloudbeaver -type d -exec chmod 775 {} \;
WORKDIR /opt/cloudbeaver/
ENTRYPOINT ["./run-server.sh"]
+35 -1
View File
@@ -10,4 +10,38 @@ IF NOT EXIST workspace\.metadata (
)
)
java %JAVA_OPTS% --add-modules=ALL-SYSTEM --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.base/jdk.internal.vm=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/sun.security.ssl=ALL-UNNAMED --add-opens=java.base/sun.security.action=ALL-UNNAMED --add-opens=java.base/sun.security.util=ALL-UNNAMED -jar %launcherJar% -product io.cloudbeaver.product.ce.product -web-config conf/cloudbeaver.conf -nl en -registryMultiLanguage
SET VMARGS_OPTS = ""
If Not Defined JAVA_OPTS (
SET VMARGS_OPTS = "-Xmx2048M"
)
java %JAVA_OPTS% ^
-Dfile.encoding=UTF-8 ^
--add-modules=ALL-SYSTEM ^
--add-opens=java.base/java.io=ALL-UNNAMED ^
--add-opens=java.base/java.lang=ALL-UNNAMED ^
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED ^
--add-opens=java.base/java.net=ALL-UNNAMED ^
--add-opens=java.base/java.nio=ALL-UNNAMED ^
--add-opens=java.base/java.nio.charset=ALL-UNNAMED ^
--add-opens=java.base/java.text=ALL-UNNAMED ^
--add-opens=java.base/java.time=ALL-UNNAMED ^
--add-opens=java.base/java.util=ALL-UNNAMED ^
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED ^
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED ^
--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED ^
--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED ^
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED ^
--add-opens=java.base/sun.security.ssl=ALL-UNNAMED ^
--add-opens=java.base/sun.security.action=ALL-UNNAMED ^
--add-opens=java.base/sun.security.util=ALL-UNNAMED ^
--add-opens=java.security.jgss/sun.security.jgss=ALL-UNNAMED ^
--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED ^
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED ^
--add-opens=java.sql/java.sql=ALL-UNNAMED ^
-jar %launcherJar% ^
-product io.cloudbeaver.product.ce.product ^
-data %workspacePath% ^
-web-config conf/cloudbeaver.conf ^
-nl en ^
-registryMultiLanguage
+33 -2
View File
@@ -4,6 +4,37 @@ launcherJar=( server/plugins/org.eclipse.equinox.launcher*.jar )
echo "Starting Cloudbeaver Server"
[ ! -d "workspace/.metadata" ] && mkdir -p workspace/.metadata && mkdir -p workspace/GlobalConfiguration/.dbeaver && [ ! -f "workspace/GlobalConfiguration/.dbeaver/data-sources.json" ] && cp conf/initial-data-sources.conf workspace/GlobalConfiguration/.dbeaver/data-sources.json
[ ! -d "workspace/.metadata" ] && mkdir -p workspace/.metadata \
&& mkdir -p workspace/GlobalConfiguration/.dbeaver \
&& [ ! -f "workspace/GlobalConfiguration/.dbeaver/data-sources.json" ] \
&& cp conf/initial-data-sources.conf workspace/GlobalConfiguration/.dbeaver/data-sources.json
java ${JAVA_OPTS} --add-modules=ALL-SYSTEM --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.base/jdk.internal.vm=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/sun.security.ssl=ALL-UNNAMED --add-opens=java.base/sun.security.action=ALL-UNNAMED --add-opens=java.base/sun.security.util=ALL-UNNAMED -jar ${launcherJar} -product io.cloudbeaver.product.ce.product -web-config conf/cloudbeaver.conf -nl en -registryMultiLanguage
java ${JAVA_OPTS} \
-Dfile.encoding=UTF-8 \
--add-modules=ALL-SYSTEM \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens=java.base/java.net=ALL-UNNAMED \
--add-opens=java.base/java.nio=ALL-UNNAMED \
--add-opens=java.base/java.nio.charset=ALL-UNNAMED \
--add-opens=java.base/java.text=ALL-UNNAMED \
--add-opens=java.base/java.time=ALL-UNNAMED \
--add-opens=java.base/java.util=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED \
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED \
--add-opens=java.base/sun.security.ssl=ALL-UNNAMED \
--add-opens=java.base/sun.security.action=ALL-UNNAMED \
--add-opens=java.base/sun.security.util=ALL-UNNAMED \
--add-opens=java.security.jgss/sun.security.jgss=ALL-UNNAMED \
--add-opens=java.security.jgss/sun.security.krb5=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED \
--add-opens=java.sql/java.sql=ALL-UNNAMED \
-jar ${launcherJar} \
-product io.cloudbeaver.product.ce.product \
-web-config conf/cloudbeaver.conf \
-nl en \
-registryMultiLanguage
+2 -1
View File
@@ -2,6 +2,7 @@
<?pde version="3.8"?>
<target name="org.jkiss.tp.cloudbeaver">
<locations>
<location path="${env_var:DBEAVER_DEVEL_ECLIPSE_PATH}/plugins" type="Directory"/>
<location path="../eclipse/Eclipse.app/Contents/Eclipse/plugins" type="Directory"/>
<location path="../eclipse/eclipse/plugins" type="Directory"/>
</locations>
</target>
+9
View File
@@ -0,0 +1,9 @@
projects:
schema:
include: ./**/*.graphqls
schema: "gql.ce"
extensions:
endpoints:
Default GraphQL Endpoint:
url: http://localhost:8080/api/gql
introspect: false
@@ -1,33 +1,37 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Model
Bundle-SymbolicName: io.cloudbeaver.model;singleton:=true
Bundle-Version: 1.0.31.qualifier
Bundle-Release-Date: 20230626
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Version: 1.0.40.qualifier
Bundle-Release-Date: 20231106
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
Require-Bundle: org.jkiss.dbeaver.data.gis;visibility:=reexport,
org.jkiss.dbeaver.model;visibility:=reexport,
org.jkiss.dbeaver.model.sm;visibility:=reexport,
org.jkiss.dbeaver.model.event;visibility:=reexport,
org.jkiss.dbeaver.model.nio;visibility:=reexport,
org.jkiss.dbeaver.registry;visibility:=reexport,
org.jkiss.dbeaver.net.ssh,
org.jkiss.bundle.graphql.java;visibility:=reexport,
org.jkiss.bundle.apache.dbcp,
com.google.gson;visibility:=reexport,
jakarta.servlet-api;visibility:=reexport
jakarta.servlet-api;bundle-version="[4.0.0,4.0.0]";visibility:=reexport
Export-Package: io.cloudbeaver,
io.cloudbeaver.auth,
io.cloudbeaver.auth.provider,
io.cloudbeaver.auth.provider.local,
io.cloudbeaver.auth.provisioning,
io.cloudbeaver.websocket,
io.cloudbeaver.model,
io.cloudbeaver.model.app,
io.cloudbeaver.model.fs,
io.cloudbeaver.model.rm,
io.cloudbeaver.model.rm.local,
io.cloudbeaver.model.rm.lock,
io.cloudbeaver.model.rm.fs.nio,
io.cloudbeaver.model.session,
io.cloudbeaver.model.user,
io.cloudbeaver.registry,
@@ -1,2 +0,0 @@
Bundle-Vendor = DBeaver Corp
Bundle-Name = Cloudbeaver Web Model
@@ -3,5 +3,4 @@ output.. = target/classes/
bin.includes = .,\
META-INF/,\
plugin.xml,\
schema/,\
OSGI-INF/
schema/
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.model</artifactId>
<version>1.0.31-SNAPSHOT</version>
<version>1.0.40-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -16,14 +16,15 @@
*/
package io.cloudbeaver;
import io.cloudbeaver.model.rm.RMUtils;
import org.eclipse.core.resources.IProject;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMControllerProvider;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.registry.BaseProjectImpl;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.Pair;
@@ -31,7 +32,7 @@ import org.jkiss.utils.Pair;
import java.nio.file.Path;
import java.util.Collection;
public class BaseWebProjectImpl extends BaseProjectImpl {
public class BaseWebProjectImpl extends BaseProjectImpl implements RMControllerProvider {
@NotNull
private final RMProject project;
@@ -61,6 +62,12 @@ public class BaseWebProjectImpl extends BaseProjectImpl {
return resourceController;
}
@NotNull
@Override
public RMProject getRMProject() {
return project;
}
@Override
public boolean isVirtual() {
return true;
@@ -17,6 +17,7 @@
package io.cloudbeaver;
import org.jkiss.dbeaver.model.access.DBAPermissionRealm;
import org.jkiss.dbeaver.model.rm.RMConstants;
/**
* General constants
@@ -25,7 +26,7 @@ public class DBWConstants {
public static final String PERMISSION_ADMIN = DBAPermissionRealm.PERMISSION_ADMIN;
public static final String PERMISSION_CONFIGURATION_MANAGER = "configuration-manager";
public static final String PERMISSION_CONFIGURATION_MANAGER = RMConstants.PERMISSION_CONFIGURATION_MANAGER;
public static final String PERMISSION_PRIVATE_PROJECT_ACCESS = "private-project-access";
public static final String PERMISSION_EDIT_STRUCTURE = "edit-meta";
@@ -33,9 +34,6 @@ public class DBWConstants {
public static final String STATE_ATTR_SIGN_IN_STATE = "state.signin";
public static final String USER_PROJECTS_FOLDER = "user-projects";
public static final String SHARED_PROJECTS_FOLDER = "shared-projects";
public enum SignInState {
GLOBAL,
EMBEDDED
@@ -144,14 +144,18 @@ public class DBWebException extends DBException implements GraphQLError {
}
private static String makeMessage(String message, Throwable cause) {
if (CommonUtils.isEmpty(message)) {
if (cause != null) {
if (cause.getMessage() != null) {
return cause.getMessage();
}
return cause.getClass().getName();
if (cause == null) {
if (CommonUtils.isEmpty(message)) {
return "Unknown internal error";
} else {
return message;
}
return "Unknown internal error";
}
if (CommonUtils.isEmpty(message)) {
if (cause.getMessage() != null) {
return cause.getMessage();
}
return cause.getClass().getName();
}
if (CommonUtils.equalObjects(message, cause.getMessage())) {
return message;
@@ -208,8 +208,8 @@ public class WebDataSourceRegistryProxy implements DBPDataSourceRegistry, DataSo
@Nullable
@Override
public DBWNetworkProfile getNetworkProfile(String name) {
return dataSourceRegistry.getNetworkProfile(name);
public DBWNetworkProfile getNetworkProfile(String source, String name) {
return dataSourceRegistry.getNetworkProfile(source, name);
}
@NotNull
@@ -0,0 +1,28 @@
/*
* 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;
import org.jkiss.dbeaver.model.DBPPage;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import java.util.Map;
public class WebPage extends DBPPage {
public WebPage(Map<String, Object> params) {
super(JSONUtils.getInteger(params, "offset"), JSONUtils.getInteger(params, "limit"));
}
}
@@ -27,7 +27,7 @@ import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.registry.rm.DataSourceRegistryRM;
import org.jkiss.dbeaver.runtime.DBWorkbench;
public class WebProjectImpl extends BaseWebProjectImpl {
public abstract class WebProjectImpl extends BaseWebProjectImpl {
private static final Log log = Log.getLog(WebProjectImpl.class);
public WebProjectImpl(
@@ -0,0 +1,39 @@
/*
* 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;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.rm.RMProject;
public class WebSessionProjectImpl extends WebProjectImpl {
private final WebSession webSession;
public WebSessionProjectImpl(@NotNull WebSession webSession, @NotNull RMProject project, @NotNull DataSourceFilter dataSourceFilter) {
super(webSession.getWorkspace(), webSession.getRmController(), webSession.getSessionContext(), project, dataSourceFilter);
this.webSession = webSession;
}
@Nullable
@Override
public DBNModel getNavigatorModel() {
return webSession.getNavigatorModel();
}
}
@@ -19,6 +19,7 @@ package io.cloudbeaver.auth;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import java.util.Map;
@@ -31,7 +32,7 @@ public interface SMAuthProviderAssigner {
@NotNull
SMAutoAssign detectAutoAssignments(
@NotNull DBRProgressMonitor monitor,
@NotNull Map<String, Object> providerConfig,
@NotNull SMAuthProviderCustomConfiguration providerConfig,
@NotNull Map<String, Object> authParameters
) throws DBException;
@@ -26,6 +26,7 @@ import org.jkiss.dbeaver.model.DBPObject;
import org.jkiss.dbeaver.model.auth.SMAuthProvider;
import org.jkiss.dbeaver.model.auth.SMSession;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import java.util.Map;
@@ -41,7 +42,7 @@ public interface SMAuthProviderExternal<AUTH_SESSION extends SMSession> extends
@NotNull
default Map<String, Object> authExternalUser(
@NotNull DBRProgressMonitor monitor,
@NotNull Map<String, Object> providerConfig, // Auth provider configuration (e.g. 3rd party auth server address)
@Nullable SMAuthProviderCustomConfiguration providerConfig, // Auth provider configuration (e.g. 3rd party auth server address)
@NotNull Map<String, Object> authParameters // Passed auth parameters (e.g. user name or password)
) throws DBException {
return authParameters;
@@ -51,7 +52,7 @@ public interface SMAuthProviderExternal<AUTH_SESSION extends SMSession> extends
@NotNull
DBWUserIdentity getUserIdentity(
@NotNull DBRProgressMonitor monitor,
@NotNull Map<String, Object> providerConfig,
@Nullable SMAuthProviderCustomConfiguration customConfiguration,
@NotNull Map<String, Object> authParameters) throws DBException;
/**
@@ -0,0 +1,34 @@
/*
* 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.auth.provisioning;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import org.jkiss.dbeaver.model.security.user.SMUserProvisioning;
import java.util.List;
public interface SMProvisioner {
@NotNull
List<SMUserProvisioning> listExternalUsers(
@NotNull WebSession webSession,
@NotNull SMAuthProviderCustomConfiguration customConfiguration,
@NotNull SMProvisioningFilter filter
) throws DBException;
}
@@ -0,0 +1,28 @@
package io.cloudbeaver.auth.provisioning;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.data.json.JSONUtils;
import java.util.Map;
public class SMProvisioningFilter {
@Nullable
private final Integer offset;
@Nullable
private final Integer limit;
public SMProvisioningFilter(Map<String, Object> params) {
this.offset = JSONUtils.getInteger(params, "offset");
this.limit = JSONUtils.getInteger(params, "limit");
}
@Nullable
public Integer getOffset() {
return offset;
}
@Nullable
public Integer getLimit() {
return limit;
}
}
@@ -25,6 +25,7 @@ import io.cloudbeaver.utils.CBModelConstants;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.utils.WebCommonUtils;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBConstants;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
@@ -40,6 +41,7 @@ import org.jkiss.dbeaver.model.navigator.DBNDataSource;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
import org.jkiss.dbeaver.model.runtime.DBRRunnableParametrized;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
@@ -52,7 +54,8 @@ import java.util.stream.Collectors;
*/
public class WebConnectionInfo {
private static final String SECURED_VALUE = "********";
private static final Log log = Log.getLog(WebConnectionInfo.class);
public static final String SECURED_VALUE = "********";
private final WebSession session;
private final DBPDataSourceContainer dataSourceContainer;
private WebServerError connectError;
@@ -63,6 +66,7 @@ public class WebConnectionInfo {
private transient Map<String, Object> savedAuthProperties;
private transient List<WebNetworkHandlerConfigInput> savedNetworkCredentials;
private transient List<DBRRunnableParametrized<WebConnectionInfo>> closeListeners = null;
public WebConnectionInfo(WebSession session, DBPDataSourceContainer ds) {
this.session = session;
@@ -322,9 +326,8 @@ public class WebConnectionInfo {
return new WebPropertyInfo[0];
}
// Fill session and user provided credentials
// Fill user provided credentials
DBPConnectionConfiguration configWithAuth = new DBPConnectionConfiguration(dataSourceContainer.getConnectionConfiguration());
session.provideAuthParameters(session.getProgressMonitor(), dataSourceContainer, configWithAuth);
// show all properties if it is a manual connection
Predicate<DBPPropertyDescriptor> predicate = CommonUtils.isEmpty(getRequiredAuth())
@@ -362,9 +365,23 @@ public class WebConnectionInfo {
this.savedNetworkCredentials = networkCredentials;
}
public void clearSavedCredentials() {
public void clearCache() {
this.savedAuthProperties = null;
this.savedNetworkCredentials = null;
this.fireCloseListeners();
}
public void fireCloseListeners() {
if (closeListeners != null) {
for (DBRRunnableParametrized<WebConnectionInfo> listener : closeListeners) {
try {
listener.run(this);
} catch (Exception e) {
log.debug(e);
}
}
closeListeners = null;
}
}
@Property
@@ -418,4 +435,12 @@ public class WebConnectionInfo {
return appConfig.isShowReadOnlyConnectionInfo();
}
public void addCloseListener(DBRRunnableParametrized<WebConnectionInfo> listener) {
if (closeListeners == null) {
closeListeners = new ArrayList<>();
}
closeListeners.add(listener);
}
}
@@ -18,10 +18,17 @@ package io.cloudbeaver.model;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerDescriptor;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.dbeaver.model.net.ssh.SSHConstants;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.registry.RegistryConstants;
import org.jkiss.dbeaver.runtime.properties.PropertySourceMap;
import org.jkiss.utils.CommonUtils;
import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -52,6 +59,7 @@ public class WebNetworkHandlerConfig {
return configuration.isEnabled();
}
@Deprecated
public SSHConstants.AuthType getAuthType() {
return CommonUtils.valueOf(SSHConstants.AuthType.class, configuration.getStringProperty(SSHConstants.PROP_AUTH_TYPE), SSHConstants.AuthType.PASSWORD);
}
@@ -64,7 +72,7 @@ public class WebNetworkHandlerConfig {
return CommonUtils.isEmpty(configuration.getPassword()) ? null : "";
}
@Deprecated // use secure properties
public String getKey() {
return CommonUtils.isEmpty(configuration.getSecureProperty(SSHConstants.PROP_KEY_VALUE)) ? null : "";
}
@@ -78,4 +86,16 @@ public class WebNetworkHandlerConfig {
return configuration.getProperties();
}
@NotNull
public Map<String, String> getSecureProperties() {
Map<String, String> secureProperties = new LinkedHashMap<>(configuration.getSecureProperties());
DBPPropertyDescriptor[] descriptor = configuration.getHandlerDescriptor().getHandlerProperties();
for (DBPPropertyDescriptor p : descriptor) {
if (p.hasFeature(RegistryConstants.ATTR_PASSWORD)) {
secureProperties.computeIfPresent(p.getId(), (k, v) -> CommonUtils.isEmpty(v) ? null : WebConnectionInfo.SECURED_VALUE);
}
}
return secureProperties;
}
}
@@ -20,6 +20,7 @@ import org.jkiss.dbeaver.model.data.json.JSONUtils;
import org.jkiss.dbeaver.model.net.DBWHandlerType;
import org.jkiss.utils.CommonUtils;
import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -61,6 +62,7 @@ public class WebNetworkHandlerConfigInput {
return JSONUtils.getString(cfg, "password");
}
@Deprecated // use secured properties
public String getKey() {
return JSONUtils.getString(cfg, "key");
}
@@ -77,4 +79,16 @@ public class WebNetworkHandlerConfigInput {
return JSONUtils.getObjectOrNull(cfg, "properties");
}
public Map<String, String> getSecureProperties() {
var secureProperties = JSONUtils.getObjectOrNull(cfg, "secureProperties");
if (secureProperties == null) {
return null;
}
var result = new LinkedHashMap<String, String>();
for (Map.Entry<String, Object> property : secureProperties.entrySet()) {
result.put(property.getKey(), CommonUtils.toString(property.getValue()));
}
return result;
}
}
@@ -88,6 +88,11 @@ public class WebPropertyInfo {
}
}
@Property
public String getHint() {
return property.getHint();
}
@Property
public int getOrder() {
return property instanceof ObjectPropertyDescriptor ? ((ObjectPropertyDescriptor) property).getOrderNumber() : -1;
@@ -116,7 +121,8 @@ public class WebPropertyInfo {
@Property
public Object getDefaultValue() throws DBException {
return property.getDefaultValue();
var defaultValue = property.getDefaultValue();
return defaultValue == null ? getValue() : defaultValue;
}
@Property
@@ -17,26 +17,17 @@
package io.cloudbeaver.model;
import io.cloudbeaver.utils.CBModelConstants;
import org.jkiss.dbeaver.model.websocket.event.MessageType;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
/**
* Web server message
*/
public class WebServerMessage {
public enum MessageType {
DEBUG,
INFO,
WARNING,
ERROR
}
private final MessageType type;
private final Instant time;
private final String message;
@@ -18,6 +18,7 @@ package io.cloudbeaver.model.app;
import io.cloudbeaver.DataSourceFilter;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.WebSessionProjectImpl;
import io.cloudbeaver.model.log.SLF4JLogHandler;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.server.WebGlobalWorkspace;
@@ -69,8 +70,10 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
}
@Override
public RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace) throws DBException {
public RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace
) throws DBException {
throw new IllegalStateException("Resource controller is not supported by " + getClass().getSimpleName());
}
@@ -173,10 +176,8 @@ public abstract class BaseWebApplication extends BaseApplicationImpl implements
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter
) {
return new WebProjectImpl(
webSession.getWorkspace(),
webSession.getRmController(),
webSession.getSessionContext(),
return new WebSessionProjectImpl(
webSession,
project,
dataSourceFilter
);
@@ -53,7 +53,8 @@ public interface WebApplication extends DBPApplication {
WebProjectImpl createProjectImpl(
@NotNull WebSession webSession,
@NotNull RMProject project,
@NotNull DataSourceFilter dataSourceFilter);
@NotNull DataSourceFilter dataSourceFilter
);
SMController createSecurityController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
@@ -61,8 +62,10 @@ public interface WebApplication extends DBPApplication {
DBSSecretController getSecretController(@NotNull SMCredentialsProvider credentialsProvider) throws DBException;
RMController createResourceController(@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace) throws DBException;
RMController createResourceController(
@NotNull SMCredentialsProvider credentialsProvider,
@NotNull DBPWorkspace workspace
) throws DBException;
DBFileController createFileController(@NotNull SMCredentialsProvider credentialsProvider);
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model.app;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import java.util.Set;
@@ -33,5 +34,6 @@ public interface WebAuthConfiguration {
Set<SMAuthProviderCustomConfiguration> getAuthCustomConfigurations();
@Nullable
SMAuthProviderCustomConfiguration getAuthProviderConfiguration(String configId);
}
@@ -0,0 +1,27 @@
/*
* 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.model.fs;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.fs.DBFVirtualFileSystem;
public class FSUtils {
@NotNull
public static String makeUniqueFsId(@NotNull DBFVirtualFileSystem fileSystem) {
return fileSystem.getType() + ":" + fileSystem.getId();
}
}
@@ -19,7 +19,7 @@ public abstract class DBNAbstractResourceManagerNode extends DBNNode implements
super(parentNode);
}
public void removeChildResourceNode(@NotNull Queue<RMResource> resourcePath) {
public void removeChildResourceNode(@NotNull Queue<String> resourcePath) {
if (children == null || resourcePath.isEmpty()) {
return;
}
@@ -49,7 +49,7 @@ public abstract class DBNAbstractResourceManagerNode extends DBNNode implements
return;
}
var expectedResource = resourcePath.poll();
var node = RMNavigatorUtils.findResourceNode(children, expectedResource);
var node = RMNavigatorUtils.findResourceNode(children, expectedResource.getName());
if (node == null) { // we are in expected parent node
DBNResourceManagerResource newResourceNode = new DBNResourceManagerResource(this, expectedResource);
children = ArrayUtils.add(DBNResourceManagerResource.class, children, newResourceNode);
@@ -101,7 +101,7 @@ public class DBNResourceManagerProject extends DBNAbstractResourceManagerNode {
return children;
}
public RMController getResourceController() {
protected RMController getResourceController() {
return ((DBNResourceManagerRoot) getParentNode()).getResourceController();
}
@@ -20,6 +20,7 @@ package io.cloudbeaver.model.rm;
import io.cloudbeaver.model.session.WebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPHiddenObject;
import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.dbeaver.model.app.DBPProject;
@@ -29,11 +30,14 @@ import org.jkiss.dbeaver.model.navigator.DBNRoot;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
import java.util.*;
public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject, RMEventListener {
private static final Log log = Log.getLog(DBNResourceManagerRoot.class);
private DBNResourceManagerProject[] projects;
private RMController resourceController;
@@ -74,6 +78,9 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
public DBNResourceManagerProject[] getChildren(DBRProgressMonitor monitor) throws DBException {
if (projects == null) {
List<? extends DBPProject> projectList = getParentNode().getModel().getModelProjects();
if (CommonUtils.isEmpty(projectList)) {
return new DBNResourceManagerProject[0];
}
SMSession session = null;
for (DBPProject project : projectList) {
session = getParentNode().getModel().getModelAuthContext().getSpaceSession(monitor, project.getWorkspace(), false);
@@ -123,10 +130,10 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
var action = event.getAction();
switch (action) {
case RESOURCE_DELETE:
deleteResourceNode(event.getProject(), event.getResourceTree());
deleteResourceNode(event.getProject(), event.getResourcePath());
break;
case RESOURCE_ADD:
addResourceNode(event.getProject(), event.getResourceTree());
addResourceNode(event.getProject(), event.getResourcePath());
break;
case PROJECT_ADD:
addProjectNode(event.getProject());
@@ -134,9 +141,19 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
}
}
private void deleteResourceNode(RMProject project, List<RMResource> resourcePath) {
@Override
protected void dispose(boolean reflect) {
RMEventManager.removeEventListener(this);
super.dispose(reflect);
}
private void deleteResourceNode(RMProject project, String resourcePath) {
if (resourcePath == null) {
return;
}
var projectNode = getProjectNode(project);
projectNode.ifPresent(dbnResourceManagerProject -> dbnResourceManagerProject.removeChildResourceNode(new ArrayDeque<>(resourcePath)));
var rmResourcePath = Arrays.asList(resourcePath.split("/"));
projectNode.ifPresent(dbnResourceManagerProject -> dbnResourceManagerProject.removeChildResourceNode(new ArrayDeque<>(rmResourcePath)));
}
@NotNull
@@ -146,9 +163,17 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
.findFirst();
}
private void addResourceNode(RMProject project, List<RMResource> resourcePath) {
private void addResourceNode(RMProject project, String resourcePath) {
if (resourcePath == null) {
return;
}
var projectNode = getProjectNode(project);
projectNode.ifPresent(dbnResourceManagerProject -> dbnResourceManagerProject.addChildResourceNode(new ArrayDeque<>(resourcePath)));
try {
var rmResourcePath = Arrays.asList(getResourceController().getResourcePath(project.getId(), resourcePath));
projectNode.ifPresent(dbnResourceManagerProject -> dbnResourceManagerProject.addChildResourceNode(new ArrayDeque<>(rmResourcePath)));
} catch (DBException e) {
log.error("Cannot add new node to resource manager tree", e);
}
}
private void addProjectNode(RMProject project) {
@@ -3,11 +3,11 @@ package io.cloudbeaver.model.rm;
import org.jkiss.dbeaver.model.rm.RMResource;
class RMNavigatorUtils {
public static DBNResourceManagerResource findResourceNode(DBNResourceManagerResource[] resourceNodes, RMResource expectedResource) {
public static DBNResourceManagerResource findResourceNode(DBNResourceManagerResource[] resourceNodes, String expectedResource) {
DBNResourceManagerResource node = null;
for (DBNResourceManagerResource resourceNode : resourceNodes) {
var nodeResource = resourceNode.getResource();
if (nodeResource.getName().equals(expectedResource.getName()) && nodeResource.isFolder() == expectedResource.isFolder()) {
if (nodeResource.getName().equals(expectedResource)) {
node = resourceNode;
break;
}
@@ -1,103 +0,0 @@
/*
* 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.model.rm;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.model.app.BaseWebApplication;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectPermission;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class RMUtils {
public static Path getRootPath() {
return DBWorkbench.getPlatform().getWorkspace().getAbsolutePath();
}
public static Path getUserProjectsPath() {
return getRootPath().resolve(DBWConstants.USER_PROJECTS_FOLDER);
}
public static Path getSharedProjectsPath() {
return getRootPath().resolve(DBWConstants.SHARED_PROJECTS_FOLDER);
}
@NotNull
public static Path getProjectPath(RMProject project) {
switch (project.getType()) {
case GLOBAL:
return getRootPath().resolve(BaseWebApplication.getInstance().getDefaultProjectName());
case SHARED:
return getSharedProjectsPath().resolve(project.getName());
default:
return getUserProjectsPath().resolve(project.getName());
}
}
/**
* Different types of project have different location on the workspace. Method returns path to the project.
*
* @param projectId project name or other identifier
* @return path to the project based on the name of projects and prefixes that it contains
*/
@NotNull
public static Path getProjectPathByName(@NotNull String projectId) throws DBException {
int divPos = projectId.indexOf("_");
if (divPos <= 0) {
throw new DBException("Bad project ID");
}
String prefix = projectId.substring(0, divPos);
String projectName = projectId.substring(divPos + 1);
switch (RMProjectType.getByPrefix(prefix)) {
case GLOBAL:
String defaultProjectName = BaseWebApplication.getInstance().getDefaultProjectName();
if (CommonUtils.isEmpty(defaultProjectName)) {
throw new DBException("Global projects are not supported");
}
return getRootPath().resolve(defaultProjectName);
case SHARED:
return getSharedProjectsPath().resolve(projectName);
default:
return getUserProjectsPath().resolve(projectName);
}
}
public static Set<String> parseProjectPermissions(Set<String> permissions) {
return permissions.stream()
.map(RMProjectPermission::fromPermission).filter(Objects::nonNull)
.flatMap(permission -> permission.getAllPermissions().stream())
.collect(Collectors.toSet());
}
public static RMProject createAnonymousProject() {
RMProject project = new RMProject("anonymous");
project.setId("anonymous");
project.setType(RMProjectType.USER);
project.setProjectPermissions(RMProjectPermission.DATA_SOURCES_EDIT.getAllPermissions().toArray(new String[0]));
return project;
}
}
@@ -19,7 +19,6 @@ package io.cloudbeaver.model.rm.local;
import io.cloudbeaver.BaseWebProjectImpl;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.rm.RMUtils;
import io.cloudbeaver.model.rm.lock.RMFileLockController;
import io.cloudbeaver.service.security.SMUtils;
import io.cloudbeaver.service.sql.WebSQLConstants;
@@ -42,8 +41,11 @@ import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.model.security.SMObjects;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.sql.DBQuotaException;
import org.jkiss.dbeaver.model.websocket.event.MessageType;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
import org.jkiss.dbeaver.registry.*;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.ArrayUtils;
@@ -71,19 +73,18 @@ public class LocalResourceController implements RMController {
private static final String FILE_REGEX = "(?U)[\\w.$()@/\\\\ -]+";
private static final String PROJECT_REGEX = "(?U)[\\w.$()@ -]+"; // slash not allowed in project name
public static final String DEFAULT_CHANGE_ID = "0";
private final DBPWorkspace workspace;
private final SMCredentialsProvider credentialsProvider;
protected final SMCredentialsProvider credentialsProvider;
private final Path rootPath;
private final Path userProjectsPath;
private final Path sharedProjectsPath;
private final String globalProjectName;
private Supplier<SMController> smControllerSupplier;
private final RMFileLockController lockController;
private final List<RMFileOperationHandler> fileHandlers;
protected final RMFileLockController lockController;
protected final List<RMFileOperationHandler> fileHandlers;
private final Map<String, BaseWebProjectImpl> projectRegistries = new LinkedHashMap<>();
@@ -121,7 +122,7 @@ public class LocalResourceController implements RMController {
return userId == null ? null : this.userProjectsPath.resolve(userId);
}
private BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException {
protected BaseWebProjectImpl getWebProject(String projectId, boolean refresh) throws DBException {
synchronized (projectRegistries) {
BaseWebProjectImpl project = projectRegistries.get(projectId);
if (project == null || refresh) {
@@ -185,7 +186,7 @@ public class LocalResourceController implements RMController {
if (credentialsProvider.hasPermission(DBWConstants.PERMISSION_ADMIN) || credentialsProvider.hasPermission(RMConstants.PERMISSION_RM_ADMIN)) {
return new ArrayList<>(Arrays.asList(listAllSharedProjects()));
}
var accessibleSharedProjects = getSecurityController().getAllAvailableObjectsPermissions(SMObjects.PROJECT);
var accessibleSharedProjects = getSecurityController().getAllAvailableObjectsPermissions(SMObjectType.project);
return accessibleSharedProjects
.stream()
@@ -240,7 +241,7 @@ public class LocalResourceController implements RMController {
}
String[] permissions = getSecurityController().getObjectPermissions(activeUserCreds.getUserId(),
projectId,
SMObjects.PROJECT
SMObjectType.project
).getPermissions();
return Arrays.stream(permissions).map(RMProjectPermission::fromPermission).collect(Collectors.toSet());
}
@@ -290,6 +291,7 @@ public class LocalResourceController implements RMController {
throw new DBException("Project '" + name + "' not created");
}
try {
log.debug("Creating project '" + project.getId() + "'");
Files.createDirectories(projectPath);
if (WebAppUtils.getWebApplication().isMultiNode()) {
createResourceTypeFolders(projectPath);
@@ -310,8 +312,12 @@ public class LocalResourceController implements RMController {
throw new DBException("Project '" + project.getName() + "' doesn't exists");
}
try {
log.debug("Deleting project '" + projectId + "'");
IOUtils.deleteDirectory(targetPath);
getSecurityController().deleteAllObjectPermissions(projectId, SMObjects.PROJECT);
getSecurityController().deleteAllObjectPermissions(projectId, SMObjectType.project);
synchronized (projectRegistries) {
projectRegistries.remove(projectId);
}
} catch (IOException e) {
throw new DBException("Error deleting project '" + project.getName() + "'", e);
}
@@ -321,6 +327,9 @@ public class LocalResourceController implements RMController {
@Override
public RMProject getProject(@NotNull String projectId, boolean readResources, boolean readProperties) throws DBException {
RMProject project = makeProjectFromId(projectId, true);
if (project == null) {
return null;
}
if (readResources) {
doProjectOperation(projectId, () -> {
project.setChildren(
@@ -347,6 +356,7 @@ public class LocalResourceController implements RMController {
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating value for property '" + propName + "' in project '" + projectId + "'");
webProject.setProjectProperty(propName, propValue);
return null;
}
@@ -356,12 +366,13 @@ public class LocalResourceController implements RMController {
@Override
public String getProjectsDataSources(@NotNull String projectId, @Nullable String[] dataSourceIds) throws DBException {
DBPProject projectMetadata = getWebProject(projectId, false);
DBPDataSourceRegistry registry = projectMetadata.getDataSourceRegistry();
registry.checkForErrors();
return doFileReadOperation(
projectId,
projectMetadata.getMetadataFolder(false),
() -> {
DBPDataSourceRegistry registry = projectMetadata.getDataSourceRegistry();
registry.refreshConfig();
registry.checkForErrors();
DataSourceConfigurationManagerBuffer buffer = new DataSourceConfigurationManagerBuffer();
Predicate<DBPDataSourceContainer> filter = null;
if (!ArrayUtils.isEmpty(dataSourceIds)) {
@@ -405,6 +416,7 @@ public class LocalResourceController implements RMController {
false
);
registry.checkForErrors();
log.debug("Save data sources configuration in project '" + projectId + "'");
((DataSourcePersistentRegistry) registry).saveDataSources();
registry.checkForErrors();
return configChanged;
@@ -424,6 +436,7 @@ public class LocalResourceController implements RMController {
DBPDataSourceContainer dataSource = registry.getDataSource(dataSourceId);
if (dataSource != null) {
log.debug("Deleting data source '" + dataSourceId + "' in project '" + projectId + "'");
registry.removeDataSource(dataSource);
} else {
log.warn("Could not find datasource " + dataSourceId + " for deletion");
@@ -440,6 +453,7 @@ public class LocalResourceController implements RMController {
@NotNull String folderPath) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "createDatasourceFolder")) {
DBPProject project = getWebProject(projectId, false);
log.debug("Creating data source folder '" + folderPath + "' in project '" + projectId + "'");
doFileWriteOperation(projectId, project.getMetadataFolder(false),
() -> {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
@@ -469,6 +483,7 @@ public class LocalResourceController implements RMController {
for (String folderPath : folderPaths) {
DBPDataSourceFolder folder = registry.getFolder(folderPath);
if (folder != null) {
log.debug("Deleting data source folder '" + folderPath + "' in project '" + projectId + "'");
registry.removeFolder(folder, dropContents);
} else {
log.warn("Can not find folder by path [" + folderPath + "] for deletion");
@@ -489,6 +504,7 @@ public class LocalResourceController implements RMController {
) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "createDatasourceFolder")) {
DBPProject project = getWebProject(projectId, false);
log.debug("Moving data source folder from '" + oldPath + "' to '" + newPath + "' in project '" + projectId + "'");
doFileWriteOperation(projectId, project.getMetadataFolder(false),
() -> {
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
@@ -567,6 +583,7 @@ public class LocalResourceController implements RMController {
if (Files.exists(targetPath)) {
throw new DBException("Resource '" + resourcePath + "' already exists");
}
log.debug("Creating resource '" + resourcePath + "' in project '" + projectId + "'");
createFolder(targetPath.getParent());
doFileWriteOperation(projectId, targetPath, () -> {
try {
@@ -596,10 +613,10 @@ public class LocalResourceController implements RMController {
var normalizedOldResourcePath = CommonUtils.normalizeResourcePath(oldResourcePath);
var normalizedNewResourcePath = CommonUtils.normalizeResourcePath(newResourcePath);
if (log.isDebugEnabled()) {
log.debug("Moving resource from '" + normalizedOldResourcePath + "' to '" + normalizedNewResourcePath + "'");
log.debug("Moving resource from '" + normalizedOldResourcePath + "' to '" + normalizedNewResourcePath +
"' in project '" + projectId + "'");
}
Path oldTargetPath = getTargetPath(projectId, normalizedOldResourcePath);
List<RMResource> rmOldResourcePath = makeResourcePath(projectId, oldTargetPath, false);
doFileWriteOperation(projectId, oldTargetPath, () -> {
if (!Files.exists(oldTargetPath)) {
@@ -622,7 +639,7 @@ public class LocalResourceController implements RMController {
return null;
});
fireRmResourceDeleteEvent(projectId, rmOldResourcePath);
fireRmResourceDeleteEvent(projectId, normalizedOldResourcePath);
fireRmResourceAddEvent(projectId, normalizedNewResourcePath);
}
@@ -636,10 +653,10 @@ public class LocalResourceController implements RMController {
* Gathers the old-new properties paths pairs and updates properties via BaseProjectImpl#moveResourcePropertiesBatch()
*/
private void movePropertiesRecursive(
@NotNull String projectId,
@NotNull Path rootResourcePath,
@NotNull String oldRootPropertiesPath,
@NotNull String newRootPropertiesPath
@NotNull String projectId,
@NotNull Path rootResourcePath,
@NotNull String oldRootPropertiesPath,
@NotNull String newRootPropertiesPath
) throws IOException, DBException {
var project = getWebProject(projectId, false);
var projectPath = getProjectPath(projectId);
@@ -660,11 +677,10 @@ public class LocalResourceController implements RMController {
public void deleteResource(@NotNull String projectId, @NotNull String resourcePath, boolean recursive) throws DBException {
try (var projectLock = lockController.lockProject(projectId, "deleteResource")) {
if (log.isDebugEnabled()) {
log.debug("Removing resource from '" + resourcePath + "'" + (recursive ? " recursive" : ""));
log.debug("Removing resource from '" + resourcePath + "' in project '" + projectId + "'" + (recursive ? " recursive" : ""));
}
validateResourcePath(resourcePath);
Path targetPath = getTargetPath(projectId, resourcePath);
List<RMResource> rmResourcePath = makeResourcePath(projectId, targetPath, recursive);
doFileWriteOperation(projectId, targetPath, () -> {
if (!Files.exists(targetPath)) {
throw new DBException("Resource '" + resourcePath + "' doesn't exists");
@@ -697,7 +713,7 @@ public class LocalResourceController implements RMController {
});
log.debug("Fire resource delete event");
fireRmResourceDeleteEvent(projectId, rmResourcePath);
fireRmResourceDeleteEvent(projectId, resourcePath);
}
}
@@ -717,6 +733,12 @@ public class LocalResourceController implements RMController {
return makeResourcePath(projectId, getTargetPath(projectId, resourcePath), false).toArray(RMResource[]::new);
}
@Nullable
@Override
public RMResource getResource(@NotNull String projectId, @NotNull String resourcePath) throws DBException {
return makeResourceFromPath(projectId, getTargetPath(projectId, resourcePath), null, false, false, false);
}
@NotNull
@Override
public byte[] getResourceContents(@NotNull String projectId, @NotNull String resourcePath) throws DBException {
@@ -757,15 +779,16 @@ public class LocalResourceController implements RMController {
}
Path targetPath = getTargetPath(projectId, resourcePath);
if (!forceOverwrite && Files.exists(targetPath)) {
throw new DBException("Resource '" + resourcePath + "' exists");
throw new DBException("Resource '" + IOUtils.getFileNameWithoutExtension(targetPath) + "' already exists");
}
doFileWriteOperation(projectId, targetPath, () -> {
createFolder(targetPath.getParent());
try {
log.debug("Writing data to resource '" + targetPath + " in project " + projectId + "'");
Files.write(targetPath, data);
} catch (IOException e) {
throw new DBException("Error reading resource '" + resourcePath + "'", e);
throw new DBException("Error writing resource '" + resourcePath + "'", e);
}
return null;
});
@@ -777,7 +800,7 @@ public class LocalResourceController implements RMController {
return DEFAULT_CHANGE_ID;
}
private void createFolder(Path targetPath) throws DBException {
protected void createFolder(Path targetPath) throws DBException {
if (!Files.exists(targetPath)) {
try {
Files.createDirectories(targetPath);
@@ -800,6 +823,7 @@ public class LocalResourceController implements RMController {
BaseWebProjectImpl webProject = getWebProject(projectId, false);
doFileWriteOperation(projectId, webProject.getMetadataFilePath(),
() -> {
log.debug("Updating resource property '" + propertyName + "' in project '" + projectId + "'");
webProject.setResourceProperty(resourcePath, propertyName, propertyValue);
return null;
}
@@ -853,9 +877,21 @@ public class LocalResourceController implements RMController {
return type.getPrefix() + "_" + projectName;
}
@Nullable
private RMProject makeProjectFromId(String projectId, boolean loadPermissions) throws DBException {
var projectName = parseProjectName(projectId);
var projectPath = getProjectPath(projectId);
if (!Files.exists(projectPath)) {
if (isPrivateProject(projectId) && isProjectOwner(projectId)) {
try {
Files.createDirectories(projectPath);
} catch (Exception e) {
throw new DBException("Failed to create project " + projectId + ": " + e.getMessage(), e);
}
} else {
return null;
}
}
Set<RMProjectPermission> permissions = Set.of();
if (loadPermissions && credentialsProvider.getActiveUserCredentials() != null) {
permissions = getProjectPermissions(projectId, projectName.getType());
@@ -923,35 +959,65 @@ public class LocalResourceController implements RMController {
}
}
private <T> T doProjectOperation(String projectId, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
protected <T> T doProjectOperation(String projectId, RMFileOperation<T> operation) throws DBException {
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.projectOpened(projectPath);
try {
fileHandler.projectOpened(projectId);
} catch (Exception e) {
if (credentialsProvider.getActiveUserCredentials() != null) {
WebAppUtils.getWebApplication().getEventController().addEvent(
new WSSessionLogUpdatedEvent(
WSEventType.SESSION_LOG_UPDATED,
credentialsProvider.getActiveUserCredentials().getSmSessionId(),
credentialsProvider.getActiveUserCredentials().getUserId(),
MessageType.ERROR,
e.getMessage()));
}
}
}
return operation.doOperation();
}
private <T> T doFileReadOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
protected <T> T doFileReadOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.beforeFileRead(projectPath, file);
try {
fileHandler.beforeFileRead(projectId, file);
} catch (Exception e) {
if (credentialsProvider.getActiveUserCredentials() != null) {
WebAppUtils.getWebApplication().getEventController().addEvent(
new WSSessionLogUpdatedEvent(
WSEventType.SESSION_LOG_UPDATED,
credentialsProvider.getActiveUserCredentials().getSmSessionId(),
credentialsProvider.getActiveUserCredentials().getUserId(),
MessageType.ERROR,
e.getMessage()));
}
log.error("Error before file reading", e);
}
}
return operation.doOperation();
}
private <T> T doFileWriteOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
var projectPath = getProjectPath(projectId);
protected <T> T doFileWriteOperation(String projectId, Path file, RMFileOperation<T> operation) throws DBException {
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.beforeFileChange(projectPath, file);
fileHandler.beforeFileChange(projectId, file);
}
T result;
try {
result = operation.doOperation();
} catch (Exception e) {
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.handleFileChangeException(projectId, file, e);
}
throw e;
}
var result = operation.doOperation();
for (RMFileOperationHandler fileHandler : fileHandlers) {
fileHandler.afterFileChange(projectPath, file, credentialsProvider.getActiveUserCredentials());
fileHandler.afterFileChange(projectId, file, credentialsProvider.getActiveUserCredentials());
}
return result;
}
private Path getProjectPath(String projectId) throws DBException {
protected Path getProjectPath(String projectId) throws DBException {
RMProjectName project = parseProjectName(projectId);
RMProjectType type = project.getType();
String projectName = project.getName();
@@ -1060,11 +1126,11 @@ public class LocalResourceController implements RMController {
RMEventManager.fireEvent(
new RMEvent(RMEvent.Action.RESOURCE_ADD,
getProject(projectId, false, false),
Arrays.asList(getResourcePath(projectId, resourcePath)))
resourcePath)
);
}
private void fireRmResourceDeleteEvent(@NotNull String projectId, @NotNull List<RMResource> resourcePath) throws DBException {
private void fireRmResourceDeleteEvent(@NotNull String projectId, @NotNull String resourcePath) throws DBException {
RMEventManager.fireEvent(
new RMEvent(RMEvent.Action.RESOURCE_DELETE,
makeProjectFromId(projectId, false),
@@ -1135,6 +1201,7 @@ public class LocalResourceController implements RMController {
public static class RMProjectName {
String prefix;
String name;
private RMProjectName(String prefix, String name) {
this.prefix = prefix;
this.name = name;
@@ -1179,9 +1246,22 @@ public class LocalResourceController implements RMController {
return RMProjectType.GLOBAL.getPrefix().equals(rmProjectName.getPrefix());
}
public static boolean isPrivateProject(String projectId, String userId) {
public static boolean isPrivateProject(String projectId) {
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix());
}
private boolean isProjectOwner(String projectId) {
var activeUserCredentials = credentialsProvider.getActiveUserCredentials();
var userId = activeUserCredentials == null ? null : activeUserCredentials.getUserId();
return isProjectOwner(projectId, userId);
}
public static boolean isProjectOwner(String projectId, String userId) {
RMProjectName rmProjectName = parseProjectNameUnsafe(projectId);
return RMProjectType.USER.getPrefix().equals(rmProjectName.getPrefix()) &&
rmProjectName.name.equals(userId);
}
}
@@ -25,24 +25,33 @@ import java.nio.file.Path;
public interface RMFileOperationHandler {
void projectOpened(@NotNull Path projectPath) throws DBException;
void projectOpened(@NotNull String projectId) throws DBException;
/**
* Executed before reading file
*/
void beforeFileRead(@NotNull Path projectPath, @NotNull Path filePath) throws DBException;
void beforeFileRead(@NotNull String projectId, @NotNull Path filePath) throws DBException;
/**
* Executed before file modification
*/
void beforeFileChange(@NotNull Path projectPath, @NotNull Path filePath) throws DBException;
void beforeFileChange(@NotNull String projectId, @NotNull Path filePath) throws DBException;
/**
* Executed after file modification
*/
void afterFileChange(
@NotNull Path projectPath,
@NotNull String projectId,
@NotNull Path filePath,
@Nullable SMCredentials smCredentials
) throws DBException;
/**
* Executed if something goes wrong in file modification
*/
void handleFileChangeException(
@NotNull String projectId,
@NotNull Path filePath,
@NotNull Throwable cause
) throws DBException;
}
@@ -18,6 +18,7 @@ package io.cloudbeaver.model.rm.lock;
import com.google.gson.Gson;
import io.cloudbeaver.model.app.WebApplication;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
@@ -71,7 +72,8 @@ public class RMFileLockController {
* @param operationName - executed operation name
* @return - lock
*/
public RMLock lockProject(String projectId, String operationName) throws DBException {
@NotNull
public RMLock lockProject(@NotNull String projectId,@NotNull String operationName) throws DBException {
synchronized (RMFileLockController.class) {
try {
createLockFolderIfNeeded();
@@ -91,6 +93,24 @@ public class RMFileLockController {
}
}
/**
* if the project is already locked, the operation will be executed as a child of the first lock,
* otherwise it creates its own lock.
*
* @param projectId - project to be locked
* @param operationName - executed operation name
* @return - lock
*/
@Nullable
public RMLock lockIfNotLocked(@NotNull String projectId, @NotNull String operationName) throws DBException {
synchronized (RMFileLockController.class) {
if (isProjectLocked(projectId)) {
return null;
}
return lockProject(projectId, operationName);
}
}
/**
* Check that project locked
*/
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model.session;
import io.cloudbeaver.model.WebServerMessage;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.websocket.CBWebSessionEventHandler;
@@ -29,6 +30,7 @@ import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.auth.impl.AbstractSessionPersistent;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
import org.jkiss.dbeaver.model.websocket.event.WSEventDeleteTempFile;
import org.jkiss.dbeaver.model.websocket.event.session.WSSessionExpiredEvent;
import java.time.Instant;
@@ -82,7 +84,7 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
synchronized (sessionEventHandlers) {
for (CBWebSessionEventHandler eventHandler : sessionEventHandlers) {
try {
eventHandler.handeWebSessionEvent(event);
eventHandler.handleWebSessionEvent(event);
} catch (DBException e) {
log.error(e.getMessage(), e);
addSessionError(e);
@@ -109,6 +111,16 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
return userContext.refresh(smAuthInfo);
}
public synchronized void refreshUserData() {
try {
userContext.refreshPermissions();
userContext.refreshAccessibleProjects();
} catch (DBException e) {
addSessionError(e);
log.error("Error refreshing accessible projects", e);
}
}
@NotNull
@Override
public SMAuthSpace getSessionSpace() {
@@ -155,10 +167,12 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
public void close() {
super.close();
var sessionExpiredEvent = new WSSessionExpiredEvent();
application.getEventController().addEvent(sessionExpiredEvent);
application.getEventController().addEvent(new WSEventDeleteTempFile(getSessionId()));
synchronized (sessionEventHandlers) {
for (CBWebSessionEventHandler sessionEventHandler : sessionEventHandlers) {
try {
sessionEventHandler.handeWebSessionEvent(sessionExpiredEvent);
sessionEventHandler.handleWebSessionEvent(sessionExpiredEvent);
} catch (DBException e) {
log.warn("Failed to send session expiration event", e);
}
@@ -191,6 +205,8 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
userContext.getAccessibleProjectIds().remove(projectId);
}
public abstract void addSessionMessage(WebServerMessage message);
@Property
public boolean isValid() {
return getRemainingTime() > 0;
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.model.session;
import io.cloudbeaver.model.WebServerMessage;
import io.cloudbeaver.model.app.WebAuthApplication;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
@@ -37,6 +38,11 @@ public class WebHeadlessSession extends BaseWebSession {
}
@Override
public void addSessionMessage(WebServerMessage message) {
}
@Override
public SMSessionPrincipal getSessionPrincipal() {
return null;
@@ -27,11 +27,11 @@ import io.cloudbeaver.model.WebAsyncTaskInfo;
import io.cloudbeaver.model.WebConnectionInfo;
import io.cloudbeaver.model.WebServerMessage;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.model.rm.RMUtils;
import io.cloudbeaver.model.user.WebUser;
import io.cloudbeaver.service.DBWSessionHandler;
import io.cloudbeaver.service.sql.WebSQLConstants;
import io.cloudbeaver.utils.CBModelConstants;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
@@ -42,6 +42,7 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBFileController;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPEvent;
import org.jkiss.dbeaver.model.access.DBAAuthCredentials;
import org.jkiss.dbeaver.model.access.DBACredentialsProvider;
import org.jkiss.dbeaver.model.app.DBPDataSourceRegistry;
@@ -50,12 +51,14 @@ import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.auth.*;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.fs.DBFFileSystemManager;
import org.jkiss.dbeaver.model.meta.Association;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.navigator.DBNModel;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.rm.RMProject;
import org.jkiss.dbeaver.model.rm.RMProjectType;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.BaseProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
@@ -63,9 +66,10 @@ import org.jkiss.dbeaver.model.runtime.ProxyProgressMonitor;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMConstants;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.model.security.SMObjects;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.security.user.SMObjectPermissions;
import org.jkiss.dbeaver.model.sql.DBQuotaException;
import org.jkiss.dbeaver.model.websocket.event.MessageType;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
@@ -82,7 +86,6 @@ import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Web session.
* Is the main source of data in web application
@@ -95,7 +98,6 @@ public class WebSession extends BaseWebSession
public static final SMSessionType CB_SESSION_TYPE = new SMSessionType("CloudBeaver");
private static final String WEB_SESSION_AUTH_CONTEXT_TYPE = "web-session";
private static final String ATTR_LOCALE = "locale";
private static final AtomicInteger TASK_ID = new AtomicInteger();
private final AtomicInteger taskCount = new AtomicInteger();
@@ -232,7 +234,9 @@ public class WebSession extends BaseWebSession
return userContext.getFileController();
}
@Override
public synchronized void refreshUserData() {
super.refreshUserData();
refreshSessionAuth();
initNavigatorModel();
@@ -398,7 +402,7 @@ public class WebSession extends BaseWebSession
private Set<String> readAccessibleConnectionIds() {
try {
return getSecurityController()
.getAllAvailableObjectsPermissions(SMObjects.DATASOURCE)
.getAllAvailableObjectsPermissions(SMObjectType.datasource)
.stream()
.map(SMObjectPermissions::getObjectId)
.collect(Collectors.toSet());
@@ -461,12 +465,36 @@ public class WebSession extends BaseWebSession
this.accessibleConnectionIds = readAccessibleConnectionIds();
}
public synchronized void addAccessibleConnectionToCache(@NotNull String dsId) {
this.accessibleConnectionIds.add(dsId);
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
connections.put(dsId, new WebConnectionInfo(this, dataSource));
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_ADD, dataSource, true));
}
}
public synchronized void removeAccessibleConnectionFromCache(@NotNull String dsId) {
var registry = getProjectById(WebAppUtils.getGlobalProjectId()).getDataSourceRegistry();
var dataSource = registry.getDataSource(dsId);
if (dataSource != null) {
this.accessibleConnectionIds.remove(dsId);
connections.remove(dsId);
// reflect changes is navigator model
registry.notifyDataSourceListeners(new DBPEvent(DBPEvent.Action.OBJECT_REMOVE, dataSource));
dataSource.dispose();
}
}
private synchronized void authAsAnonymousUser() throws DBException {
if (!application.getAppConfiguration().isAnonymousAccessEnabled()) {
return;
}
SMAuthInfo authInfo = getSecurityController().authenticateAnonymousUser(this.id, getSessionParameters(), CB_SESSION_TYPE);
updateSMSession(authInfo);
notifySessionAuthChange();
}
@NotNull
@@ -568,6 +596,7 @@ public class WebSession extends BaseWebSession
}
public void removeConnection(WebConnectionInfo connectionInfo) {
connectionInfo.clearCache();
synchronized (connections) {
connections.remove(connectionInfo.getId());
}
@@ -587,7 +616,6 @@ public class WebSession extends BaseWebSession
log.error("Error closing web session tokens");
}
this.userContext.setUser(null);
super.close();
}
@@ -697,15 +725,20 @@ public class WebSession extends BaseWebSession
synchronized (sessionMessages) {
sessionMessages.add(message);
}
addSessionEvent(new WSSessionLogUpdatedEvent());
addSessionEvent(new WSSessionLogUpdatedEvent(
WSEventType.SESSION_LOG_UPDATED,
this.userContext.getSmSessionId(),
this.userContext.getUserId(),
MessageType.ERROR,
message.getMessage()));
}
public void addInfoMessage(String message) {
addSessionMessage(new WebServerMessage(WebServerMessage.MessageType.INFO, message));
addSessionMessage(new WebServerMessage(MessageType.INFO, message));
}
public void addWarningMessage(String message) {
addSessionMessage(new WebServerMessage(WebServerMessage.MessageType.WARNING, message));
addSessionMessage(new WebServerMessage(MessageType.WARNING, message));
}
public List<WebServerMessage> readLog(Integer maxEntries, Boolean clearLog) {
@@ -866,7 +899,11 @@ public class WebSession extends BaseWebSession
// Auth credentials provider
// Adds auth properties passed from web (by user)
@Override
public boolean provideAuthParameters(@NotNull DBRProgressMonitor monitor, @NotNull DBPDataSourceContainer dataSourceContainer, @NotNull DBPConnectionConfiguration configuration) {
public boolean provideAuthParameters(
@NotNull DBRProgressMonitor monitor,
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration
) {
try {
// Properties from nested auth sessions
for (DBACredentialsProvider contextCredentialsProvider : getContextCredentialsProviders()) {
@@ -984,7 +1021,10 @@ public class WebSession extends BaseWebSession
}
public void deleteSessionProject(@Nullable WebProjectImpl project) {
getWorkspace().remoteProject((WebProjectImpl) project);
if (project != null) {
project.dispose();
}
getWorkspace().removeProject(project);
if (navigatorModel != null) {
navigatorModel.getRoot().removeProject(project);
}
@@ -1011,6 +1051,15 @@ public class WebSession extends BaseWebSession
}
}
@NotNull
public DBFFileSystemManager getFileSystemManager(String projectId) throws DBException {
var project = getProjectById(projectId);
if (project == null) {
throw new DBException("Project not found: " + projectId);
}
return project.getFileSystemManager();
}
private class SessionProgressMonitor extends BaseProgressMonitor {
@Override
public void beginTask(String name, int totalWork) {
@@ -17,7 +17,6 @@
package io.cloudbeaver.model.session;
import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.DBWUserIdentity;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.auth.SMAuthProviderExternal;
@@ -38,7 +37,6 @@ import org.jkiss.utils.CommonUtils;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -103,7 +101,6 @@ public class WebSessionAuthProcessor {
String userId = curUser.getUserId();
var securityController = webSession.getSecurityController();
Map<String, Object> providerConfig = Collections.emptyMap();
var newAuthInfos = new ArrayList<WebAuthInfo>();
for (Map.Entry<SMAuthConfigurationReference, Object> entry : authInfo.getAuthData().entrySet()) {
SMAuthConfigurationReference authConfiguration = entry.getKey();
@@ -115,15 +112,6 @@ public class WebSessionAuthProcessor {
SMAuthProviderExternal<?> authProviderExternal = authProviderInstance instanceof SMAuthProviderExternal<?> ?
(SMAuthProviderExternal<?>) authProviderInstance : null;
boolean providerDisabled = !isProviderEnabled(providerId);
if (configMode || webSession.hasPermission(DBWConstants.PERMISSION_ADMIN)) {
// 1. Admin can authorize in any providers
// 2. When it authorizes in non-local provider for the first time we force linkUser flag
if (providerDisabled && webSession.getUser() != null) {
linkWithActiveUser = true;
}
}
SMSession authSession;
if (authProviderExternal != null && !configMode && !alreadyLoggedIn) {
@@ -138,7 +126,10 @@ public class WebSessionAuthProcessor {
}
DBWUserIdentity userIdentity = null;
var providerConfigId = authConfiguration.getAuthProviderConfigurationId();
var providerConfig = WebAppUtils.getWebAuthApplication()
.getAuthConfiguration()
.getAuthProviderConfiguration(providerConfigId);
if (authProviderExternal != null) {
try {
userIdentity =
@@ -17,7 +17,6 @@
package io.cloudbeaver.model.session;
import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.rm.RMUtils;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.app.DBPPlatform;
@@ -25,6 +24,7 @@ import org.jkiss.dbeaver.model.app.DBPProject;
import org.jkiss.dbeaver.model.app.DBPWorkspace;
import org.jkiss.dbeaver.model.auth.SMSessionContext;
import org.jkiss.dbeaver.model.impl.auth.SessionContextImpl;
import org.jkiss.dbeaver.model.rm.RMUtils;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.utils.CommonUtils;
@@ -92,7 +92,7 @@ public class WebSessionWorkspace implements DBPWorkspace {
}
@Override
public DBPProject getProject(@NotNull String projectName) {
public WebProjectImpl getProject(@NotNull String projectName) {
for (WebProjectImpl project : accessibleProjects) {
if (project.getName().equals(projectName)) {
return project;
@@ -140,7 +140,7 @@ public class WebSessionWorkspace implements DBPWorkspace {
accessibleProjects.add(project);
}
void remoteProject(WebProjectImpl project) {
void removeProject(WebProjectImpl project) {
accessibleProjects.remove(project);
}
@@ -80,16 +80,21 @@ public class WebUserContext implements SMCredentialsProvider {
* refresh context state based on new token from security manager
*
* @param smAuthInfo - auth info from security manager
* @return - true if context changed
* @throws DBException - if user already authorized and new token come from another user
*/
public synchronized boolean refresh(SMAuthInfo smAuthInfo) throws DBException {
if (smAuthInfo.getAuthStatus() != SMAuthStatus.SUCCESS || smAuthInfo.getSmAccessToken() == null) {
throw new DBCException("Authorization did not complete successfully");
}
if (smAuthInfo.getAuthPermissions() == null) {
if (smAuthInfo.getAuthPermissions() == null && !isAuthorizedInSecurityManager()) {
throw new DBCException("Required information about session permissions is missing");
}
return refresh(smAuthInfo.getSmAccessToken(), smAuthInfo.getSmRefreshToken(), smAuthInfo.getAuthPermissions());
boolean sessionChanged = !CommonUtils.equalObjects(smSessionId, smAuthInfo.getAuthPermissions().getSessionId());
if (smAuthInfo.getAuthStatus() != SMAuthStatus.SUCCESS || (sessionChanged && smAuthInfo.getSmAccessToken() == null)) {
throw new DBCException("Authorization did not complete successfully");
}
if (sessionChanged) {
return refresh(smAuthInfo.getSmAccessToken(), smAuthInfo.getSmRefreshToken(), smAuthInfo.getAuthPermissions());
}
return false;
}
public synchronized boolean refresh(
@@ -108,30 +113,30 @@ public class WebUserContext implements SMCredentialsProvider {
smAuthPermissions.getSessionId(),
smAuthPermissions.getPermissions()
);
this.refreshToken = smRefreshToken;
setRefreshToken(smRefreshToken);
setUserPermissions(smAuthPermissions.getPermissions());
this.securityController = application.createSecurityController(this);
this.adminSecurityController = application.getAdminSecurityController(this);
this.secretController = application.getSecretController(this);
this.rmController = application.createResourceController(this, workspace);
this.fileController = application.createFileController(this);
if (isSessionChanged) {
this.smSessionId = smAuthPermissions.getSessionId();
setUser(smAuthPermissions.getUserId() == null ? null : new WebUser(securityController.getCurrentUser()));
this.accessibleProjectIds.clear();
this.accessibleProjectIds.addAll(
Arrays.stream(rmController.listAccessibleProjects()).map(RMProject::getId).collect(Collectors.toSet())
);
refreshAccessibleProjects();
}
return isSessionChanged;
}
public synchronized void refreshAccessibleProjects() throws DBException {
this.accessibleProjectIds.clear();
this.accessibleProjectIds.addAll(
Arrays.stream(rmController.listAccessibleProjects()).map(RMProject::getId).collect(Collectors.toSet())
);
}
public synchronized void refreshSMSession() throws DBException {
if (smCredentials == null || refreshToken == null) {
return;
}
var newTokens = securityController.refreshSession(refreshToken);
this.refreshToken = newTokens.getSmRefreshToken();
setRefreshToken(newTokens.getSmRefreshToken());
this.smCredentials = new SMCredentials(
newTokens.getSmAccessToken(),
smCredentials.getUserId(),
@@ -204,6 +209,7 @@ public class WebUserContext implements SMCredentialsProvider {
*/
public synchronized void refreshPermissions() throws DBException {
if (isAuthorizedInSecurityManager()) {
log.debug("refresh permissions " + getUserId() + " " + getSmSessionId());
setUserPermissions(securityController.getTokenPermissions().getPermissions());
} else {
setUserPermissions(getDefaultPermissions());
@@ -238,4 +244,8 @@ public class WebUserContext implements SMCredentialsProvider {
public Set<String> getAccessibleProjectIds() {
return accessibleProjectIds;
}
private void setRefreshToken(@Nullable String refreshToken) {
this.refreshToken = refreshToken;
}
}
@@ -15,16 +15,25 @@ import org.jkiss.dbeaver.model.security.exception.SMRefreshTokenExpiredException
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
public class SMUtils {
public static boolean isAdmin(SMCredentialsProvider webSession) {
return webSession.hasPermission(DBWConstants.PERMISSION_ADMIN);
}
public static boolean isAdmin(@NotNull Set<String> permissions) {
return permissions.contains(DBWConstants.PERMISSION_ADMIN);
}
public static boolean isRMAdmin(SMCredentialsProvider webSession) {
return isAdmin(webSession) || webSession.hasPermission(RMConstants.PERMISSION_RM_ADMIN);
}
public static boolean isRMAdmin(@NotNull Set<String> permissions) {
return isAdmin(permissions) || permissions.contains(RMConstants.PERMISSION_RM_ADMIN);
}
public static boolean hasProjectPermission(
SMCredentialsProvider credentialsProvider,
RMProject project,
@@ -26,7 +26,9 @@ import org.jkiss.dbeaver.model.struct.DBSAttributeBase;
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Web query results info.
@@ -82,6 +84,18 @@ public class WebSQLResultsInfo {
return null;
}
@NotNull
public Set<DBDRowIdentifier> getRowIdentifiers() {
Set<DBDRowIdentifier> rowIdentifiers = new HashSet<>();
for (DBDAttributeBinding column : attributes) {
DBDRowIdentifier rowIdentifier = column.getRowIdentifier();
if (rowIdentifier != null) {
rowIdentifiers.add(rowIdentifier);
}
}
return rowIdentifiers;
}
public DBSAttributeBase getAttribute(String attributeName) {
DBPDataSource dataSource = dataContainer.getDataSource();
@@ -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;
@@ -54,6 +57,14 @@ public class WebAppUtils {
return (WebApplication) DBWorkbench.getPlatform().getApplication();
}
public static WebAuthApplication getWebAuthApplication() throws DBException {
WebApplication application = getWebApplication();
if (!WebAuthApplication.class.isAssignableFrom(application.getClass())) {
throw new DBException("The current application doesn't contain authorization configuration");
}
return (WebAuthApplication) application;
}
public static SMAuthenticationManager getAuthManager(WebApplication application) throws DBException {
var smController = application.createSecurityController(new NoAuthCredentialsProvider());
if (!SMAuthenticationManager.class.isAssignableFrom(smController.getClass())) {
@@ -144,12 +155,7 @@ public class WebAppUtils {
@NotNull
public static StringBuilder getAuthApiPrefix(String serviceId) throws DBException {
WebApplication application = getWebApplication();
if (!WebAuthApplication.class.isAssignableFrom(application.getClass())) {
throw new DBException("The current application doesn't contain authorization configuration");
}
WebAuthApplication webAuthApplication = (WebAuthApplication) application;
return getAuthApiPrefix(webAuthApplication, serviceId);
return getAuthApiPrefix(getWebAuthApplication(), serviceId);
}
@NotNull
@@ -206,4 +212,12 @@ public class WebAppUtils {
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;
}
}
@@ -88,11 +88,25 @@ public class WebDataSourceUtils {
if (cfgInput.getPassword() != null) {
handlerConfig.setPassword(cfgInput.getPassword());
}
if (cfgInput.getKey() != null) {
setSecureProperties(handlerConfig, cfgInput, true);
if (cfgInput.getKey() != null) { // backward compatibility
handlerConfig.setSecureProperty(SSHConstants.PROP_KEY_VALUE, cfgInput.getKey());
}
}
private static void setSecureProperties(DBWHandlerConfiguration handlerConfig, WebNetworkHandlerConfigInput cfgInput, boolean ignoreNulls) {
var secureProperties = cfgInput.getSecureProperties();
if (secureProperties == null) {
return;
}
for (var pr : secureProperties.entrySet()) {
if (ignoreNulls && pr.getValue() == null) {
continue;
}
handlerConfig.setSecureProperty(pr.getKey(), pr.getValue());
}
}
@Nullable
public static DBPDataSourceContainer getLocalOrGlobalDataSource(
WebApplication application, WebSession webSession, @Nullable String projectId, String connectionId
@@ -121,7 +135,8 @@ public class WebDataSourceUtils {
public static void updateHandlerCredentials(DBWHandlerConfiguration handlerCfg, WebNetworkHandlerConfigInput webConfig) {
handlerCfg.setUserName(webConfig.getUserName());
handlerCfg.setPassword(webConfig.getPassword());
handlerCfg.setSecureProperty(SSHConstants.PROP_KEY_VALUE, webConfig.getKey());
setSecureProperties(handlerCfg, webConfig, false);
handlerCfg.setSecureProperty(SSHConstants.PROP_KEY_VALUE, webConfig.getKey()); // backward compatibility
}
@@ -130,18 +130,16 @@ public class WebEventUtils {
String projectId,
WebSession session,
String resourcePath,
RMResource[] resourceParsedPath,
WSConstants.EventAction eventAction,
WSResourceProperty property
) {
addRmResourceUpdatedEvent(projectId, session, resourcePath, resourceParsedPath, eventAction, property, null);
addRmResourceUpdatedEvent(projectId, session, resourcePath, eventAction, property, null);
}
public static void addRmResourceUpdatedEvent(
String projectId,
WebSession session,
String resourcePath,
RMResource[] resourceParsedPath,
WSConstants.EventAction eventAction,
WSResourceProperty property,
String details
@@ -154,7 +152,6 @@ public class WebEventUtils {
session.getUserId(),
projectId,
resourcePath,
resourceParsedPath,
property,
details
);
@@ -165,7 +162,6 @@ public class WebEventUtils {
session.getUserId(),
projectId,
resourcePath,
resourceParsedPath,
property,
details
);
@@ -176,7 +172,6 @@ public class WebEventUtils {
session.getUserId(),
projectId,
resourcePath,
resourceParsedPath,
property,
details
);
@@ -20,7 +20,8 @@ import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
public interface CBWebSessionEventHandler {
void handeWebSessionEvent(WSEvent event) throws DBException;
void handleWebSessionEvent(WSEvent event) throws DBException;
void close();
}
@@ -1,13 +1,12 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Community Product
Bundle-SymbolicName: io.cloudbeaver.product.ce;singleton:=true
Bundle-Version: 23.1.1.qualifier
Bundle-Release-Date: 20230626
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Version: 23.2.4.qualifier
Bundle-Release-Date: 20231106
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
Require-Bundle: io.cloudbeaver.server
Bundle-Localization: OSGI-INF/l10n/bundle
Automatic-Module-Name: io.cloudbeaver.product.ce
@@ -1,2 +0,0 @@
Bundle-Vendor = DBeaver Corp
Bundle-Name = Cloudbeaver CE bundle
@@ -2,5 +2,4 @@ source.. = src/
output.. = target/classes/
bin.includes = .,\
META-INF/,\
OSGI-INF/,\
plugin.xml
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.product.ce</artifactId>
<version>23.1.1-SNAPSHOT</version>
<version>23.2.4-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -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.76.qualifier
Bundle-Release-Date: 20230626
Bundle-Version: 1.0.85.qualifier
Bundle-Release-Date: 20231106
Bundle-Vendor: DBeaver Corp
Bundle-ActivationPolicy: lazy
Automatic-Module-Name: io.cloudbeaver.resources.drivers.base
@@ -9,6 +9,6 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.resources.drivers.base</artifactId>
<version>1.0.76-SNAPSHOT</version>
<version>1.0.85-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -1,11 +1,11 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Vendor: %Bundle-Vendor
Bundle-Name: %Bundle-Name
Bundle-Vendor: DBeaver Corp
Bundle-Name: Cloudbeaver Web Server
Bundle-SymbolicName: io.cloudbeaver.server;singleton:=true
Bundle-Version: 23.1.1.qualifier
Bundle-Release-Date: 20230626
Bundle-RequiredExecutionEnvironment: JavaSE-11
Bundle-Version: 23.2.4.qualifier
Bundle-Release-Date: 20231106
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy
Bundle-Activator: io.cloudbeaver.server.CBPlatformActivator
Bundle-ClassPath: .
@@ -34,5 +34,4 @@ Export-Package: io.cloudbeaver,
io.cloudbeaver.service.session,
io.cloudbeaver.service.sql
Import-Package: org.slf4j
Bundle-Localization: OSGI-INF/l10n/bundle
Automatic-Module-Name: io.cloudbeaver.server
@@ -1,3 +0,0 @@
Bundle-Vendor = DBeaver Corp
Bundle-Name = Cloudbeaver Web Server
@@ -2,7 +2,6 @@ source.. = src/
output.. = target/classes/
bin.includes = .,\
META-INF/,\
OSGI-INF/,\
schema/,\
static/,\
plugin.xml
@@ -57,8 +57,11 @@
<eventHandler class="io.cloudbeaver.server.events.WSRmResourceUpdatedEventHandlerImpl">
<topic id="cb_scripts"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSPermissionUpdatedEventHandler">
<topic id="cb_permissions"/>
<eventHandler class="io.cloudbeaver.server.events.WSObjectPermissionUpdatedEventHandler">
<topic id="cb_object_permissions"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSSubjectPermissionUpdatedEventHandler">
<topic id="cb_subject_permissions"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSProjectUpdatedEventHandler">
<topic id="cb_projects"/>
@@ -66,6 +69,15 @@
<eventHandler class="io.cloudbeaver.server.events.WSUserSecretEventHandlerImpl">
<topic id="cb_user_secret"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSLogEventHandler">
<topic id="cb_session_log"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSEventHandlerWorkspaceConfigUpdate">
<topic id="cb_workspace_configuration"/>
</eventHandler>
<eventHandler class="io.cloudbeaver.server.events.WSDeleteTempFileHandler">
<topic id="cb_delete_temp_folder"/>
</eventHandler>
</extension>
</plugin>
+1 -1
View File
@@ -10,7 +10,7 @@
<relativePath>../</relativePath>
</parent>
<artifactId>io.cloudbeaver.server</artifactId>
<version>23.1.1-SNAPSHOT</version>
<version>23.2.4-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
@@ -3,6 +3,13 @@ scalar Object
# Date/Time
scalar DateTime
input PageInput {
limit: Int
offset: Int
}
directive @since(version: String!) repeatable on OBJECT|SCALAR|QUERY|MUTATION|FIELD|VARIABLE_DEFINITION|OBJECT|FIELD_DEFINITION|ARGUMENT_DEFINITION|INTERFACE|ENUM|ENUM_VALUE|INPUT_OBJECT|INPUT_FIELD_DEFINITION
type Query
type Mutation
@@ -12,6 +12,8 @@ type ObjectPropertyInfo {
displayName: String
# Property description
description: String
# Property hint
hint: String @since(version: "23.2.3")
# Property category (may be used if object has a lot of properties)
category: String
# Property data type (int, String, etc)
@@ -117,6 +119,7 @@ type ServerConfig {
hostName: String! @deprecated # use container id instead
containerId: String!
defaultAuthRole: String
defaultUserTeam: String # [23.2.2]
anonymousAccessEnabled: Boolean!
supportsCustomConnections: Boolean!
@@ -282,15 +285,17 @@ type NetworkHandlerDescriptor {
properties: [ObjectPropertyInfo!]!
}
# SSH network handler config. Name without prefix only for backward compatibility
type NetworkHandlerConfig {
id: ID!
enabled: Boolean!
authType: NetworkHandlerAuthType!
authType: NetworkHandlerAuthType! @deprecated # use properties
userName: String
password: String
key: String
key: String @deprecated # use secured properties
savePassword: Boolean!
properties: Object!
secureProperties: Object!
}
# Connection instance
@@ -426,12 +431,13 @@ input NavigatorSettingsInput {
input NetworkHandlerConfigInput {
id: ID!
enabled: Boolean
authType: NetworkHandlerAuthType
authType: NetworkHandlerAuthType @deprecated # use properties
userName: String
password: String
key: String
key: String @deprecated # use secured properties
savePassword: Boolean
properties: Object
secureProperties: Object
}
# Configuration of particular connection. Used for new connection create. Includes auth info
@@ -25,7 +25,12 @@ enum CBServerEventId {
cb_rm_resource_deleted,
cb_rm_project_added,
cb_rm_project_removed
cb_rm_project_removed,
cb_object_permissions_updated,
cb_subject_permissions_updated,
cb_database_output_log_updated
}
# Events sent by client
@@ -43,7 +48,11 @@ enum CBEventTopic {
cb_datasource,
cb_datasource_folder,
cb_scripts,
cb_projects
cb_projects,
cb_object_permissions,
cb_subject_permissions,
cb_database_output_log,
cb_delete_temp_folder
}
# Base server event interface
@@ -122,6 +131,12 @@ type CBProjectUpdateEvent implements CBServerEvent {
projectId: String!
}
# Subject permission update event
type CBSubjectPermissionUpdateEvent implements CBServerEvent {
id: CBServerEventId!
topicId: CBEventTopic
}
# Topic subscription event
type CBTopicEvent implements CBClientEvent {
id: CBClientEventId!
@@ -142,6 +157,22 @@ type CBProjectsActiveEvent implements CBClientEvent {
projectIds: [String!]! # list of active projects
}
# Database output log event
type CBDatabaseOutputLogEvent implements CBServerEvent {
id: CBServerEventId!
topicId: CBEventTopic
contextId: String!
messages: [WSOutputLogInfo!]!
eventTimestamp: Int!
}
# Define the type for WSOutputLogInfo
type WSOutputLogInfo {
severity: String
message: String
# Add more fields as needed
}
extend type Query {
emptyEvent: Boolean
}
@@ -59,7 +59,9 @@ type NavigatorNodeInfo {
# Node human readable name
name: String
#Node full name
fullName: String
fullName: String @deprecated # Use name parameter (23.2.0)
#Node plain name (23.2.0)
plainName: String
# Node icon path
icon: String
# Node description
@@ -67,13 +69,17 @@ type NavigatorNodeInfo {
# Node type
nodeType: String
# Can this property have child nodes?
hasChildren: Boolean
hasChildren: Boolean!
# Project id of the node
projectId: String
# Associated object. Maybe null for non-database objects
object: DatabaseObjectInfo
# Associated object. Return value depends on the node type - connectionId for connection node, resource path for resource node, etc.
# null - if node currently not support this property
objectId: String @since(version: "23.2.4")
# Supported features: item, container, leaf
# canDelete, canRename
features: [ String! ]
@@ -82,9 +88,18 @@ type NavigatorNodeInfo {
# If is different than properties. It doesn't perform any expensive operation and doesn't require authentication.
nodeDetails: [ ObjectPropertyInfo! ]
folder: Boolean
inline: Boolean
navigable: Boolean
folder: Boolean!
inline: Boolean!
navigable: Boolean!
filtered: Boolean!
# Reads node filter. Expensive invocation, read only when it is really needed
filter: NavigatorNodeFilter
}
type NavigatorNodeFilter {
include: [String!]
exclude: [String!]
}
type DatabaseCatalog {
@@ -93,6 +108,7 @@ type DatabaseCatalog {
}
type DatabaseStructContainers {
parentNode: NavigatorNodeInfo
catalogList: [ DatabaseCatalog! ]!
schemaList: [ NavigatorNodeInfo! ]!
supportsCatalogChange: Boolean!
@@ -133,6 +149,10 @@ extend type Mutation {
navDeleteNodes( nodePaths: [ID!]! ): Int
# Moves nodes with specified IDs to the connection folder
navMoveNodesToFolder( nodePaths: [ID!]!, folderPath: ID!): Boolean
navMoveNodesToFolder( nodePaths: [ID!]!, folderPath: ID!): Boolean!
# Sets filter for the folder node. If both include and exclude are null then filter is removed.
# Node must be refreshed after applying filters. Node children can be changed
navSetFolderFilter( nodePath: ID!, include: [String!], exclude: [String!]): Boolean!
}
@@ -268,7 +268,9 @@ extend type Query {
contextId: ID!,
connectionId: ID!,
resultsId: ID!,
columnNames: [String!]
columnNames: [String!],
functions: [String!],
showDuplicatesOnly: Boolean
): String!
}
@@ -287,7 +289,8 @@ extend type Mutation {
sql: String!,
resultId: ID,
filter: SQLDataFilter,
dataFormat: ResultDataFormat # requested data format. May be ignored by server
dataFormat: ResultDataFormat, # requested data format. May be ignored by server
readLogs: Boolean # added 23.2.1
): AsyncTaskInfo!
# Read data from table
@@ -222,6 +222,17 @@ public class WebServiceUtils extends WebCommonUtils {
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials
) {
saveAuthProperties(dataSourceContainer, configuration, authProperties, saveCredentials, sharedCredentials, false);
}
public static void saveAuthProperties(
@NotNull DBPDataSourceContainer dataSourceContainer,
@NotNull DBPConnectionConfiguration configuration,
@Nullable Map<String, Object> authProperties,
boolean saveCredentials,
boolean sharedCredentials,
boolean isTest
) {
dataSourceContainer.setSavePassword(saveCredentials);
dataSourceContainer.setSharedCredentials(sharedCredentials);
@@ -242,12 +253,14 @@ public class WebServiceUtils extends WebCommonUtils {
// Read save credentials
DBAAuthCredentials credentials = configuration.getAuthModel().loadCredentials(dataSourceContainer, configuration);
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
if (isTest) {
var currentAuthProps = new HashMap<String, String>();
for (Map.Entry<String, Object> stringObjectEntry : authProperties.entrySet()) {
var value = stringObjectEntry.getValue() == null ? null : stringObjectEntry.getValue().toString();
currentAuthProps.put(stringObjectEntry.getKey(), value);
}
configuration.setAuthProperties(currentAuthProps);
}
configuration.setAuthProperties(currentAuthProps);
if (!authProperties.isEmpty()) {
// Make new Gson parser with type adapters to deserialize into existing credentials
@@ -264,25 +277,6 @@ public class WebServiceUtils extends WebCommonUtils {
}
}
public static void updateConnectionFromConfig(DBPDataSourceContainer dataSource, WebConnectionConfig config) throws DBWebException {
setConnectionConfiguration(dataSource.getDriver(), dataSource.getConnectionConfiguration(), config);
dataSource.setName(config.getName());
dataSource.setDescription(config.getDescription());
if (config.getFolder() != null) {
dataSource.setFolder(dataSource.getRegistry().getFolder(config.getFolder()));
} else {
dataSource.setFolder(null);
}
getGlobalDataSourceRegistry().getAllFolders().clear();
saveAuthProperties(
dataSource,
dataSource.getConnectionConfiguration(),
config.getCredentials(),
config.isSaveCredentials(),
config.isSharedCredentials()
);
}
public static DBNBrowseSettings parseNavigatorSettings(Map<String, Object> settingsMap) {
return gson.fromJson(
gson.toJsonTree(settingsMap), DataSourceNavigatorSettings.class);
@@ -19,12 +19,15 @@ package io.cloudbeaver.model;
import io.cloudbeaver.DBWebException;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebCommonUtils;
import org.jkiss.dbeaver.model.connection.DBPAuthModelDescriptor;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.utils.CommonUtils;
import java.util.Arrays;
import java.util.function.Predicate;
/**
* WebDatabaseAuthModel
@@ -73,8 +76,12 @@ public class WebDatabaseAuthModel {
public WebPropertyInfo[] getProperties() throws DBWebException {
DBPPropertySource credentialsSource = model.createCredentialsSource(null, null);
Predicate<DBPPropertyDescriptor> predicate = CommonUtils.isEmpty(getRequiredAuth())
? p -> true
: p -> WebCommonUtils.isAuthPropertyApplicable(p, webSession.getContextCredentialsProviders());
return Arrays.stream(credentialsSource.getProperties())
.filter(p -> WebServiceUtils.isAuthPropertyApplicable(p, webSession.getContextCredentialsProviders()))
.filter(predicate)
.map(p -> new WebPropertyInfo(webSession, p, credentialsSource)).toArray(WebPropertyInfo[]::new);
}
@@ -213,6 +213,7 @@ public class WebDatabaseDriverInfo {
return new String[0];
}
return NetworkHandlerRegistry.getInstance().getDescriptors(driver).stream()
.filter(h -> !h.isDesktopHandler())
.map(NetworkHandlerDescriptor::getId).toArray(String[]::new);
}
@@ -240,10 +241,8 @@ public class WebDatabaseDriverInfo {
@Property
public boolean getRequiresServerName() {
if (driver.getSampleURL() == null) {
return false;
}
return driver.getSampleURL().contains(URL_SERVER_FIELD);
return driver.getSupportedPageFields().contains(DBConstants.PROP_SERVER) ||
(driver.getSampleURL() != null && driver.getSampleURL().contains(URL_SERVER_FIELD));
}
@Property
@@ -212,4 +212,9 @@ public class WebServerConfig {
public String getDefaultAuthRole() {
return application.getDefaultAuthRole();
}
@Property
public String getDefaultUserTeam() {
return application.getAppConfiguration().getDefaultUserTeam();
}
}
@@ -17,7 +17,8 @@
package io.cloudbeaver.model.user;
import io.cloudbeaver.WebServiceUtils;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.auth.SMAuthProviderFederated;
import io.cloudbeaver.auth.provisioning.SMProvisioner;
import io.cloudbeaver.registry.WebAuthProviderConfiguration;
import io.cloudbeaver.registry.WebAuthProviderDescriptor;
import io.cloudbeaver.server.CBApplication;
@@ -70,6 +71,10 @@ public class WebAuthProviderInfo {
return descriptor.isConfigurable();
}
public boolean isFederated() {
return descriptor.getInstance() instanceof SMAuthProviderFederated;
}
public boolean isTrusted() {
return descriptor.isTrusted();
}
@@ -78,6 +83,10 @@ public class WebAuthProviderInfo {
return descriptor.isPrivate();
}
public boolean isSupportProvisioning() {
return descriptor.getInstance() instanceof SMProvisioner;
}
public List<WebAuthProviderConfiguration> getConfigurations() {
List<WebAuthProviderConfiguration> result = new ArrayList<>();
for (SMAuthProviderCustomConfiguration cfg : CBApplication.getInstance().getAppConfiguration().getAuthCustomConfigurations()) {
@@ -16,6 +16,7 @@
*/
package io.cloudbeaver.server;
import org.jkiss.dbeaver.model.auth.AuthInfo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
@@ -24,7 +25,6 @@ import io.cloudbeaver.auth.CBAuthConstants;
import io.cloudbeaver.model.app.BaseWebApplication;
import io.cloudbeaver.model.app.WebAuthApplication;
import io.cloudbeaver.model.app.WebAuthConfiguration;
import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.registry.WebDriverRegistry;
import io.cloudbeaver.registry.WebServiceRegistry;
import io.cloudbeaver.server.jetty.CBJettyServer;
@@ -33,6 +33,7 @@ import io.cloudbeaver.service.DBWServiceServerConfigurator;
import io.cloudbeaver.service.security.SMControllerConfiguration;
import io.cloudbeaver.service.session.WebSessionManager;
import io.cloudbeaver.utils.WebAppUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.service.datalocation.Location;
import org.jkiss.code.NotNull;
@@ -49,7 +50,7 @@ import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration;
import org.jkiss.dbeaver.model.security.SMConstants;
import org.jkiss.dbeaver.model.security.SMObjects;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.websocket.event.WSEventController;
import org.jkiss.dbeaver.model.websocket.event.WSServerConfigurationChangedEvent;
import org.jkiss.dbeaver.registry.BaseApplicationImpl;
@@ -107,6 +108,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
protected int serverPort = CBConstants.DEFAULT_SERVER_PORT;
private String serverHost = null;
private String serverName = null;
private String sslConfigurationPath = null;
private String contentRoot = CBConstants.DEFAULT_CONTENT_ROOT;
private String rootURI = CBConstants.DEFAULT_ROOT_URI;
private String servicesURI = CBConstants.DEFAULT_SERVICES_URI;
@@ -257,11 +259,13 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
if (CommonUtils.isEmpty(localHostAddress)) {
localHostAddress = System.getProperty(CBConstants.VAR_CB_LOCAL_HOST_ADDR);
}
if (CommonUtils.isEmpty(localHostAddress) || "127.0.0.1".equals(localHostAddress) || "::0".equals(localHostAddress)) {
if (CommonUtils.isEmpty(localHostAddress) || "127.0.0.1".equals(localHostAddress) || "::0".equals(
localHostAddress)) {
localHostAddress = "localhost";
}
final Runtime runtime = Runtime.getRuntime();
initializeAdditionalConfiguration();
Location instanceLoc = Platform.getInstanceLocation();
try {
@@ -278,8 +282,10 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
log.debug(GeneralUtils.getProductName() + " " + GeneralUtils.getProductVersion() + " is starting"); //$NON-NLS-1$
log.debug("\tOS: " + System.getProperty(StandardConstants.ENV_OS_NAME) + " " + System.getProperty(StandardConstants.ENV_OS_VERSION) + " (" + System.getProperty(StandardConstants.ENV_OS_ARCH) + ")");
log.debug("\tJava version: " + System.getProperty(StandardConstants.ENV_JAVA_VERSION) + " by " + System.getProperty(StandardConstants.ENV_JAVA_VENDOR) + " (" + System.getProperty(StandardConstants.ENV_JAVA_ARCH) + "bit)");
log.debug("\tOS: " + System.getProperty(StandardConstants.ENV_OS_NAME) + " " + System.getProperty(
StandardConstants.ENV_OS_VERSION) + " (" + System.getProperty(StandardConstants.ENV_OS_ARCH) + ")");
log.debug("\tJava version: " + System.getProperty(StandardConstants.ENV_JAVA_VERSION) + " by " + System.getProperty(
StandardConstants.ENV_JAVA_VENDOR) + " (" + System.getProperty(StandardConstants.ENV_JAVA_ARCH) + "bit)");
log.debug("\tInstall path: '" + SystemVariablesResolver.getInstallPath() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
log.debug("\tGlobal workspace: '" + instanceLoc.getURL() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
log.debug("\tMemory available " + (runtime.totalMemory() / (1024 * 1024)) + "Mb/" + (runtime.maxMemory() / (1024 * 1024)) + "Mb");
@@ -309,7 +315,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
{
// Perform services initialization
for (DBWServiceInitializer wsi : WebServiceRegistry.getInstance().getWebServices(DBWServiceInitializer.class)) {
for (DBWServiceInitializer wsi : WebServiceRegistry.getInstance()
.getWebServices(DBWServiceInitializer.class)) {
try {
wsi.initializeService(this);
} catch (Exception e) {
@@ -319,14 +326,6 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
{
try {
initializeSecurityController();
} catch (Exception e) {
log.error("Error initializing database", e);
return;
}
}
try {
initializeServer();
} catch (DBException e) {
@@ -334,11 +333,22 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
return;
}
try {
initializeSecurityController();
} catch (Exception e) {
log.error("Error initializing database", e);
return;
}
if (configurationMode) {
// Try to configure automatically
performAutoConfiguration(configPath.toFile().getParentFile());
} else if (appConfiguration.isGrantConnectionsAccessToAnonymousTeam() && !isMultiNode()) {
grantAnonymousAccessToConnections(appConfiguration, "auto-grant");
} else if (!isMultiNode()) {
if (appConfiguration.isGrantConnectionsAccessToAnonymousTeam()) {
grantAnonymousAccessToConnections(appConfiguration, CBConstants.ADMIN_AUTO_GRANT);
}
grantPermissionsToConnections();
}
if (enableSecurityManager) {
@@ -360,6 +370,10 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
return;
}
protected void initializeAdditionalConfiguration() {
}
/**
* Configures server automatically.
* Called on startup
@@ -372,7 +386,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
String autoAdminName = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
String autoAdminPassword = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD);
if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty(autoAdminPassword)) {
if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty(
autoAdminPassword)) {
// Try to load from auto config file
if (configPath.exists()) {
File autoConfigFile = new File(configPath, CBConstants.AUTO_CONFIG_FILE_NAME);
@@ -386,13 +401,15 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
autoAdminName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
autoAdminPassword = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD);
} catch (IOException e) {
log.error("Error loading auto configuration file '" + autoConfigFile.getAbsolutePath() + "'", e);
log.error("Error loading auto configuration file '" + autoConfigFile.getAbsolutePath() + "'",
e);
}
}
}
}
if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty(autoAdminPassword)) {
if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty(
autoAdminPassword)) {
log.info("No auto configuration was found. Server must be configured manually");
return;
}
@@ -488,6 +505,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
protected Path loadServerConfiguration() throws DBException {
Path path = super.loadServerConfiguration();
File runtimeConfigFile = getRuntimeAppConfigFile();
if (runtimeConfigFile.exists()) {
log.debug("Runtime configuration [" + runtimeConfigFile.getAbsolutePath() + "]");
@@ -507,7 +525,9 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
parseConfiguration(configPath.toFile());
}
// Set default preferences
PrefUtils.setDefaultPreferenceValue(ModelPreferences.getPreferences(), ModelPreferences.UI_DRIVERS_HOME, getDriversLocation());
PrefUtils.setDefaultPreferenceValue(ModelPreferences.getPreferences(),
ModelPreferences.UI_DRIVERS_HOME,
getDriversLocation());
}
private void parseConfiguration(File configFile) throws DBException {
@@ -535,6 +555,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
serverName = JSONUtils.getString(serverConfig, CBConstants.PARAM_SERVER_NAME, serverName);
sslConfigurationPath = JSONUtils.getString(serverConfig, CBConstants.PARAM_SSL_CONFIGURATION_PATH, sslConfigurationPath);
contentRoot = WebAppUtils.getRelativePath(
JSONUtils.getString(serverConfig, CBConstants.PARAM_CONTENT_ROOT, contentRoot), homeFolder);
rootURI = readRootUri(serverConfig);
@@ -544,10 +565,14 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
workspaceLocation = WebAppUtils.getRelativePath(
JSONUtils.getString(serverConfig, CBConstants.PARAM_WORKSPACE_LOCATION, workspaceLocation), homeFolder);
maxSessionIdleTime = JSONUtils.getLong(serverConfig, CBConstants.PARAM_SESSION_EXPIRE_PERIOD, maxSessionIdleTime);
maxSessionIdleTime = JSONUtils.getLong(serverConfig,
CBConstants.PARAM_SESSION_EXPIRE_PERIOD,
maxSessionIdleTime);
develMode = JSONUtils.getBoolean(serverConfig, CBConstants.PARAM_DEVEL_MODE, develMode);
enableSecurityManager = JSONUtils.getBoolean(serverConfig, CBConstants.PARAM_SECURITY_MANAGER, enableSecurityManager);
enableSecurityManager = JSONUtils.getBoolean(serverConfig,
CBConstants.PARAM_SECURITY_MANAGER,
enableSecurityManager);
//SM config
gson.fromJson(
gson.toJsonTree(JSONUtils.getObject(serverConfig, CBConstants.PARAM_SM_CONFIGURATION)),
@@ -629,7 +654,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
protected void readProductConfiguration(Map<String, Object> serverConfig, Gson gson, String homeFolder) throws DBException {
protected void readProductConfiguration(Map<String, Object> serverConfig, Gson gson, String homeFolder)
throws DBException {
String productConfigPath = WebAppUtils.getRelativePath(
JSONUtils.getString(
serverConfig,
@@ -645,7 +671,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
log.error("Product configuration file not found (" + productConfigFile.getAbsolutePath() + "'");
} else {
log.debug("Load product configuration from '" + productConfigFile.getAbsolutePath() + "'");
try (Reader reader = new InputStreamReader(new FileInputStream(productConfigFile), StandardCharsets.UTF_8)) {
try (Reader reader = new InputStreamReader(new FileInputStream(productConfigFile),
StandardCharsets.UTF_8)) {
productConfiguration.putAll(JSONUtils.parseMap(gson, reader));
} catch (Exception e) {
throw new DBException("Error reading product configuration", e);
@@ -665,6 +692,22 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
}
protected Map<String, Object> readConnectionsPermissionsConfiguration(Path parentPath) {
String permissionsConfigPath = WebAppUtils.getRelativePath(CBConstants.DEFAULT_DATASOURCE_PERMISSIONS_CONFIGURATION,
parentPath);
File permissionsConfigFile = new File(permissionsConfigPath);
if (permissionsConfigFile.exists()) {
log.debug("Load permissions configuration from '" + permissionsConfigFile.getAbsolutePath() + "'");
try (Reader reader = new InputStreamReader(new FileInputStream(permissionsConfigFile),
StandardCharsets.UTF_8)) {
return JSONUtils.parseMap(getGson(), reader);
} catch (Exception e) {
log.error("Error reading permissions configuration", e);
}
}
return null;
}
protected Map<String, Object> readConfiguration(File configFile) throws DBException {
Map<String, Object> configProps = new LinkedHashMap<>();
if (configFile.exists()) {
@@ -702,7 +745,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
public Map<String, Object> readConfigurationFile(File configFile) throws DBException {
try (Reader reader = new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8)) {
return JSONUtils.parseMap(getGson(), reader);
} catch (IOException e) {
} catch (Exception e) {
throw new DBException("Error parsing server configuration", e);
}
}
@@ -784,7 +827,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
@NotNull String newServerURL,
@NotNull String adminName,
@Nullable String adminPassword,
@NotNull List<WebAuthInfo> authInfoList,
@NotNull List<AuthInfo> authInfoList,
long sessionExpireTime,
@NotNull CBAppConfig appConfig,
@Nullable SMCredentialsProvider credentialsProvider
@@ -820,7 +863,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
configurationMode = CommonUtils.isEmpty(serverName);
// Reloading configuration by services
for (DBWServiceServerConfigurator wsc : WebServiceRegistry.getInstance().getWebServices(DBWServiceServerConfigurator.class)) {
for (DBWServiceServerConfigurator wsc : WebServiceRegistry.getInstance()
.getWebServices(DBWServiceServerConfigurator.class)) {
try {
wsc.reloadConfiguration(appConfig);
} catch (Exception e) {
@@ -844,7 +888,7 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
protected abstract void finishSecurityServiceConfiguration(
@NotNull String adminName,
@Nullable String adminPassword,
@NotNull List<WebAuthInfo> authInfoList
@NotNull List<AuthInfo> authInfoList
) throws DBException;
public synchronized void flushConfiguration(SMCredentialsProvider credentialsProvider) throws DBException {
@@ -857,11 +901,13 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
String anonymousTeamId = appConfig.getAnonymousUserTeam();
var securityController = getSecurityController();
for (DBPDataSourceContainer ds : WebServiceUtils.getGlobalDataSourceRegistry().getDataSources()) {
var datasourcePermissions = securityController.getObjectPermissions(anonymousTeamId, ds.getId(), SMObjects.DATASOURCE);
var datasourcePermissions = securityController.getObjectPermissions(anonymousTeamId,
ds.getId(),
SMObjectType.datasource);
if (ArrayUtils.isEmpty(datasourcePermissions.getPermissions())) {
securityController.setObjectPermissions(
Set.of(ds.getId()),
SMObjects.DATASOURCE,
SMObjectType.datasource,
Set.of(anonymousTeamId),
Set.of(SMConstants.DATA_SOURCE_ACCESS_PERMISSION),
adminName
@@ -873,6 +919,37 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
}
private void grantPermissionsToConnections() {
try {
var globalRegistry = WebDataSourceUtils.getGlobalDataSourceRegistry();
var permissionsConfiguration = readConnectionsPermissionsConfiguration(globalRegistry.getProject()
.getMetadataFolder(false));
if (permissionsConfiguration == null) {
return;
}
for (var entry : permissionsConfiguration.entrySet()) {
var dataSourceId = entry.getKey();
var ds = globalRegistry.getDataSource(dataSourceId);
if (ds == null) {
log.error("Connection " + dataSourceId + " is not found in project " + globalRegistry.getProject()
.getName());
}
List<String> permissions = JSONUtils.getStringList(permissionsConfiguration, dataSourceId);
var securityController = getSecurityController();
securityController.deleteAllObjectPermissions(dataSourceId, SMObjectType.datasource);
securityController.setObjectPermissions(
Set.of(dataSourceId),
SMObjectType.datasource,
new HashSet<>(permissions),
Set.of(SMConstants.DATA_SOURCE_ACCESS_PERMISSION),
CBConstants.ADMIN_AUTO_GRANT
);
}
} catch (DBException e) {
log.error("Error granting permissions to connections", e);
}
}
protected void saveRuntimeConfig(
String newServerName,
String newServerURL,
@@ -921,7 +998,10 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
var originServerConfig = getServerConfigProps(this.originalConfigurationProperties); // get server properties from original configuration file
rootConfig.put("server", serverConfigProperties);
if (!CommonUtils.isEmpty(newServerName)) {
copyConfigValue(originServerConfig, serverConfigProperties, CBConstants.PARAM_SERVER_NAME, newServerName);
copyConfigValue(originServerConfig,
serverConfigProperties,
CBConstants.PARAM_SERVER_NAME,
newServerName);
}
if (!CommonUtils.isEmpty(newServerURL)) {
copyConfigValue(
@@ -929,10 +1009,14 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
if (sessionExpireTime > 0) {
copyConfigValue(
originServerConfig, serverConfigProperties, CBConstants.PARAM_SESSION_EXPIRE_PERIOD, sessionExpireTime);
originServerConfig,
serverConfigProperties,
CBConstants.PARAM_SESSION_EXPIRE_PERIOD,
sessionExpireTime);
}
var databaseConfigProperties = new LinkedHashMap<String, Object>();
Map<String, Object> oldRuntimeDBConfig = JSONUtils.getObject(originServerConfig, CBConstants.PARAM_DB_CONFIGURATION);
Map<String, Object> oldRuntimeDBConfig = JSONUtils.getObject(originServerConfig,
CBConstants.PARAM_DB_CONFIGURATION);
if (!CommonUtils.isEmpty(databaseConfiguration) && !isDistributed()) {
for (Map.Entry<String, Object> mp : databaseConfiguration.entrySet()) {
copyConfigValue(oldRuntimeDBConfig, databaseConfigProperties, mp.getKey(), mp.getValue());
@@ -948,23 +1032,41 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
copyConfigValue(
oldAppConfig, appConfigProperties, "anonymousAccessEnabled", appConfig.isAnonymousAccessEnabled());
copyConfigValue(
oldAppConfig, appConfigProperties, "supportsCustomConnections", appConfig.isSupportsCustomConnections());
oldAppConfig,
appConfigProperties,
"supportsCustomConnections",
appConfig.isSupportsCustomConnections());
copyConfigValue(
oldAppConfig, appConfigProperties, "publicCredentialsSaveEnabled", appConfig.isPublicCredentialsSaveEnabled());
oldAppConfig,
appConfigProperties,
"publicCredentialsSaveEnabled",
appConfig.isPublicCredentialsSaveEnabled());
copyConfigValue(
oldAppConfig, appConfigProperties, "adminCredentialsSaveEnabled", appConfig.isAdminCredentialsSaveEnabled());
oldAppConfig,
appConfigProperties,
"adminCredentialsSaveEnabled",
appConfig.isAdminCredentialsSaveEnabled());
copyConfigValue(
oldAppConfig, appConfigProperties, "enableReverseProxyAuth", appConfig.isEnabledReverseProxyAuth());
copyConfigValue(
oldAppConfig, appConfigProperties, "forwardProxy", appConfig.isEnabledForwardProxy());
copyConfigValue(
oldAppConfig, appConfigProperties, "linkExternalCredentialsWithUser", appConfig.isLinkExternalCredentialsWithUser());
oldAppConfig,
appConfigProperties,
"linkExternalCredentialsWithUser",
appConfig.isLinkExternalCredentialsWithUser());
copyConfigValue(
oldAppConfig, appConfigProperties, "redirectOnFederatedAuth", appConfig.isRedirectOnFederatedAuth());
copyConfigValue(
oldAppConfig, appConfigProperties, CBConstants.PARAM_RESOURCE_MANAGER_ENABLED, appConfig.isResourceManagerEnabled());
oldAppConfig,
appConfigProperties,
CBConstants.PARAM_RESOURCE_MANAGER_ENABLED,
appConfig.isResourceManagerEnabled());
copyConfigValue(
oldAppConfig, appConfigProperties, CBConstants.PARAM_SHOW_READ_ONLY_CONN_INFO, appConfig.isShowReadOnlyConnectionInfo());
oldAppConfig,
appConfigProperties,
CBConstants.PARAM_SHOW_READ_ONLY_CONN_INFO,
appConfig.isShowReadOnlyConnectionInfo());
copyConfigValue(
oldAppConfig,
appConfigProperties,
@@ -972,7 +1074,8 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
appConfig.isGrantConnectionsAccessToAnonymousTeam());
Map<String, Object> resourceQuotas = new LinkedHashMap<>();
Map<String, Object> originResourceQuotas = JSONUtils.getObject(oldAppConfig, CBConstants.PARAM_RESOURCE_QUOTAS);
Map<String, Object> originResourceQuotas = JSONUtils.getObject(oldAppConfig,
CBConstants.PARAM_RESOURCE_QUOTAS);
for (Map.Entry<String, Object> mp : appConfig.getResourceQuotas().entrySet()) {
copyConfigValue(originResourceQuotas, resourceQuotas, mp.getKey(), mp.getValue());
}
@@ -1086,7 +1189,12 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
// gets info about patterns from original configuration file and saves it to runtime config
private void copyConfigValue(Map<String, Object> oldConfig, Map<String, Object> newConfig, String key, Object defaultValue) {
private void copyConfigValue(
Map<String, Object> oldConfig,
Map<String, Object> newConfig,
String key,
Object defaultValue
) {
Object value = oldConfig.get(key);
if (value instanceof Map && defaultValue instanceof Map) {
Map<String, Object> subValue = new LinkedHashMap<>();
@@ -1117,4 +1225,13 @@ public abstract class CBApplication extends BaseWebApplication implements WebAut
}
return containerId;
}
@Nullable
public Path getSslConfigurationPath() {
if (sslConfigurationPath == null) {
return null;
}
var sslConfiguration = Path.of(sslConfigurationPath);
return sslConfiguration.isAbsolute() ? sslConfiguration : getHomeDirectory().resolve(sslConfiguration);
}
}
@@ -16,9 +16,9 @@
*/
package io.cloudbeaver.server;
import org.jkiss.dbeaver.model.auth.AuthInfo;
import io.cloudbeaver.auth.NoAuthCredentialsProvider;
import io.cloudbeaver.model.rm.local.LocalResourceController;
import io.cloudbeaver.model.session.WebAuthInfo;
import io.cloudbeaver.service.security.CBEmbeddedSecurityController;
import io.cloudbeaver.service.security.EmbeddedSecurityControllerFactory;
import org.jkiss.code.NotNull;
@@ -31,7 +31,6 @@ import org.jkiss.dbeaver.model.auth.SMCredentialsProvider;
import org.jkiss.dbeaver.model.rm.RMController;
import org.jkiss.dbeaver.model.security.SMAdminController;
import org.jkiss.dbeaver.model.security.SMController;
import org.jkiss.dbeaver.registry.BasePlatformImpl;
import org.jkiss.dbeaver.registry.LocalFileController;
import org.jkiss.dbeaver.runtime.DBWorkbench;
@@ -94,7 +93,7 @@ public class CBApplicationCE extends CBApplication {
protected void finishSecurityServiceConfiguration(
@NotNull String adminName,
@Nullable String adminPassword,
@NotNull List<WebAuthInfo> authInfoList
@NotNull List<AuthInfo> authInfoList
) throws DBException {
if (securityController instanceof CBEmbeddedSecurityController) {
((CBEmbeddedSecurityController) securityController).finishConfiguration(adminName, adminPassword, authInfoList);
@@ -28,6 +28,7 @@ public class CBConstants {
public static final String PARAM_SERVER_PORT = "serverPort";
public static final String PARAM_SERVER_HOST = "serverHost";
public static final String PARAM_SERVER_NAME = "serverName";
public static final String PARAM_SSL_CONFIGURATION_PATH = "sslConfigurationPath";
public static final String PARAM_CONTENT_ROOT = "contentRoot";
public static final String PARAM_SERVER_URL = "serverURL";
public static final String PARAM_ROOT_URI = "rootURI";
@@ -60,6 +61,7 @@ public class CBConstants {
public static final String DEFAULT_DRIVERS_LOCATION = DEFAULT_DEPLOY_LOCATION + "/drivers";
public static final String DEFAULT_WORKSPACE_LOCATION = DEFAULT_DEPLOY_LOCATION + "/workspace";
public static final String DEFAULT_PRODUCT_CONFIGURATION = "conf/product.conf";
public static final String DEFAULT_DATASOURCE_PERMISSIONS_CONFIGURATION = "data-sources-permissions.json";
public static final String DEFAULT_ADMIN_NAME = "cbadmin";
public static final String DEFAULT_ADMIN_TEAM = "admin";
@@ -79,4 +81,5 @@ public class CBConstants {
public static final String APPLICATION_JSON = "application/json";
public static final String QUOTA_PROP_FILE_LIMIT = "dataExportFileSizeLimit";
public static final String ADMIN_AUTO_GRANT = "auto-grant";
}
@@ -22,8 +22,10 @@ import io.cloudbeaver.server.jobs.SessionStateJob;
import io.cloudbeaver.server.jobs.WebSessionMonitorJob;
import io.cloudbeaver.service.session.WebSessionManager;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
@@ -39,6 +41,7 @@ import org.jkiss.dbeaver.model.impl.app.DefaultCertificateStorage;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.qm.QMRegistry;
import org.jkiss.dbeaver.model.qm.QMUtils;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.registry.BasePlatformImpl;
@@ -49,6 +52,7 @@ import org.jkiss.dbeaver.runtime.qm.QMLogFileWriter;
import org.jkiss.dbeaver.runtime.qm.QMRegistryImpl;
import org.jkiss.dbeaver.utils.ContentUtils;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.IOUtils;
import org.osgi.framework.Bundle;
import java.io.IOException;
@@ -67,6 +71,7 @@ public class CBPlatform extends BasePlatformImpl {
public static final String PLUGIN_ID = "io.cloudbeaver.server"; //$NON-NLS-1$
private static final Log log = Log.getLog(CBPlatform.class);
private static final String TEMP_FILE_FOLDER = "temp-sql-upload-files";
public static final String WORK_DATA_FOLDER_NAME = ".work-data";
@@ -159,6 +164,17 @@ public class CBPlatform extends BasePlatformImpl {
new SessionStateJob(this)
.scheduleMonitor();
new AbstractJob("Delete temp folder") {
@Override
protected IStatus run(DBRProgressMonitor monitor) {
try {
IOUtils.deleteDirectory(getTempFolder(monitor, TEMP_FILE_FOLDER));
} catch (IOException e) {
throw new RuntimeException(e);
}
return Status.OK_STATUS;
}
}.schedule();
log.info("Web platform initialized (" + (System.currentTimeMillis() - startTime) + "ms)");
}
@@ -177,7 +193,7 @@ public class CBPlatform extends BasePlatformImpl {
this.queryManager.dispose();
//queryManager = null;
}
DataSourceProviderRegistry.getInstance().dispose();
DataSourceProviderRegistry.dispose();
if (workspace != null) {
try {
@@ -0,0 +1,53 @@
/*
* 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.server.events;
import io.cloudbeaver.server.CBPlatform;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.websocket.WSEventHandler;
import org.jkiss.dbeaver.model.websocket.event.WSEventDeleteTempFile;
import org.jkiss.utils.IOUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class WSDeleteTempFileHandler implements WSEventHandler<WSEventDeleteTempFile> {
private static final Log log = Log.getLog(WSDeleteTempFileHandler.class);
private static final String TEMP_FILE_FOLDER = "temp-sql-upload-files";
public void resetTempFolder(String sessionId) {
Path path = CBPlatform.getInstance()
.getTempFolder(new VoidProgressMonitor(), TEMP_FILE_FOLDER)
.resolve(sessionId);
if (Files.exists(path)) {
try {
IOUtils.deleteDirectory(path);
} catch (IOException e) {
log.error("Error deleting temp path", e);
}
}
}
@Override
public void handleEvent(@NotNull WSEventDeleteTempFile event) {
resetTempFolder(event.getSessionId());
}
}
@@ -0,0 +1,35 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2023 DBeaver Corp
*
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of DBeaver Corp and its suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to DBeaver Corp and its suppliers
* and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from DBeaver Corp.
*/
package io.cloudbeaver.server.events;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.WorkspaceConfigEventManager;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSWorkspaceConfigurationChangedEvent;
public class WSEventHandlerWorkspaceConfigUpdate extends WSDefaultEventHandler<WSWorkspaceConfigurationChangedEvent> {
private static final Log log = Log.getLog(WSEventHandlerWorkspaceConfigUpdate.class);
@Override
public void handleEvent(@NotNull WSWorkspaceConfigurationChangedEvent event) {
String configFileName = event.getConfigFilePath();
WorkspaceConfigEventManager.fireConfigChangedEvent(configFileName);
super.handleEvent(event);
}
}
@@ -0,0 +1,33 @@
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2023 DBeaver Corp
*
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of DBeaver Corp and its suppliers, if any.
* The intellectual and technical concepts contained
* herein are proprietary to DBeaver Corp and its suppliers
* and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from DBeaver Corp.
*/
package io.cloudbeaver.server.events;
import io.cloudbeaver.model.WebServerMessage;
import io.cloudbeaver.model.session.BaseWebSession;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.websocket.event.WSSessionLogUpdatedEvent;
public class WSLogEventHandler extends WSDefaultEventHandler<WSSessionLogUpdatedEvent> {
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSSessionLogUpdatedEvent event) {
activeUserSession.addSessionMessage(new WebServerMessage(event.getMessageType(), event.getMessage()));
}
protected boolean isAcceptableInSession(@NotNull BaseWebSession activeUserSession, @NotNull WSSessionLogUpdatedEvent event) {
return WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId());
}
}
@@ -0,0 +1,121 @@
/*
* 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.server.events;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.model.session.WebSession;
import io.cloudbeaver.utils.WebAppUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.security.SMObjectType;
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;
import java.util.List;
public class WSObjectPermissionUpdatedEventHandler extends WSDefaultEventHandler<WSObjectPermissionEvent> {
private static final Log log = Log.getLog(WSObjectPermissionUpdatedEventHandler.class);
@Override
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSObjectPermissionEvent event) {
try {
// we have accessible data sources only in web session
if (event.getSmObjectType() == SMObjectType.datasource && !(activeUserSession instanceof WebSession)) {
return;
}
var objectId = event.getObjectId();
boolean isAccessibleNow;
switch (event.getSmObjectType()) {
case project:
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
var accessibleProjectIds = activeUserSession.getUserContext().getAccessibleProjectIds();
if (accessibleProjectIds.contains(event.getObjectId())) {
return;
}
activeUserSession.addSessionProject(objectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.create(
event.getSessionId(),
event.getUserId(),
objectId
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
activeUserSession.removeSessionProject(objectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.delete(
event.getSessionId(),
event.getUserId(),
objectId
)
);
}
break;
case datasource:
var webSession = (WebSession) activeUserSession;
var dataSources = List.of(objectId);
var project = webSession.getProjectById(WebAppUtils.getGlobalProjectId());
if (project == null) {
log.error("Project " + WebAppUtils.getGlobalProjectId() +
" is not found in session " + activeUserSession.getSessionId());
return;
}
if (WSEventType.OBJECT_PERMISSIONS_UPDATED.getEventId().equals(event.getId())) {
isAccessibleNow = webSession.findWebConnectionInfo(objectId) != null;
if (isAccessibleNow) {
return;
}
webSession.addAccessibleConnectionToCache(objectId);
webSession.addSessionEvent(
WSDataSourceEvent.create(
event.getSessionId(),
event.getUserId(),
WebAppUtils.getGlobalProjectId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
} else if (WSEventType.OBJECT_PERMISSIONS_DELETED.getEventId().equals(event.getId())) {
webSession.removeAccessibleConnectionFromCache(objectId);
webSession.addSessionEvent(
WSDataSourceEvent.delete(
event.getSessionId(),
event.getUserId(),
WebAppUtils.getGlobalProjectId(),
dataSources,
WSDataSourceProperty.CONFIGURATION
)
);
}
}
} catch (DBException e) {
log.error("Error on changing permissions for project " +
event.getObjectId() + " in session " + activeUserSession.getSessionId(), e);
}
}
@Override
protected boolean isAcceptableInSession(@NotNull BaseWebSession activeUserSession, @NotNull WSObjectPermissionEvent event) {
return activeUserSession.getUserContext().getUser() != null && super.isAcceptableInSession(activeUserSession, event);
}
}
@@ -1,100 +0,0 @@
/*
* 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.server.events;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.server.CBPlatform;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.security.SMObjectPermissionsGrant;
import org.jkiss.dbeaver.model.security.SMObjects;
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class WSPermissionUpdatedEventHandler extends WSDefaultEventHandler<WSObjectPermissionEvent> {
private static final Log log = Log.getLog(WSPermissionUpdatedEventHandler.class);
private volatile Set<String> subjectsWithProjectAccess;
@Override
public void handleEvent(@NotNull WSObjectPermissionEvent event) {
if (!SMObjects.PROJECT_OBJECT_TYPE_ID.equals(event.getSmObjectType().getObjectType())) {
return;
}
var smController = CBPlatform.getInstance().getApplication().getSecurityController();
try {
var permissionGrants = smController.getObjectPermissionGrants(event.getObjectId(), event.getSmObjectType());
subjectsWithProjectAccess = permissionGrants.stream()
.map(SMObjectPermissionsGrant::getSubjectId)
.collect(Collectors.toSet());
super.handleEvent(event);
subjectsWithProjectAccess = Set.of();
} catch (DBException e) {
log.error("Cannot get permission grants", e);
}
}
@Override
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSObjectPermissionEvent event) {
try {
var user = activeUserSession.getUserContext().getUser();
var projectId = event.getObjectId();
var userSubjects = new HashSet<>(Set.of(user.getTeams()));
userSubjects.add(user.getUserId());
var accessibleProjectIds = activeUserSession.getUserContext().getAccessibleProjectIds();
var isAccessibleNow = accessibleProjectIds.contains(projectId);
var shouldBeAccessible = subjectsWithProjectAccess.stream().anyMatch(userSubjects::contains);
if (shouldBeAccessible && !isAccessibleNow) {
// adding project to session cache
activeUserSession.addSessionProject(projectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.create(
event.getSessionId(),
event.getUserId(),
projectId
)
);
} else if (!shouldBeAccessible && isAccessibleNow) {
// removing project from session cache
activeUserSession.removeSessionProject(projectId);
activeUserSession.addSessionEvent(
WSProjectUpdateEvent.delete(
event.getSessionId(),
event.getUserId(),
projectId
)
);
};
} catch (DBException e) {
log.error("Error on changing permissions for project " + event.getObjectId() + " in session " + event.getSessionId(), e);
}
}
@Override
protected boolean isAcceptableInSession(@NotNull BaseWebSession activeUserSession, @NotNull WSObjectPermissionEvent event) {
return activeUserSession.getUserContext().getUser() != null && super.isAcceptableInSession(activeUserSession, event);
}
}
@@ -43,35 +43,28 @@ public class WSRmResourceUpdatedEventHandlerImpl extends WSAbstractProjectEventH
@Override
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSResourceUpdatedEvent event) {
if (activeUserSession instanceof WebSession) {
var parsedResourcePath = event.getResourceParsedPath();
var resourceParsedPath = parsedResourcePath instanceof RMResource[]
? (RMResource[]) parsedResourcePath
: gson.fromJson(gson.toJson(parsedResourcePath), RMResource[].class);
var webSession = (WebSession) activeUserSession;
acceptChangesInNavigatorTree(
WSEventType.valueById(event.getId()),
resourceParsedPath,
event.getResourcePath(),
webSession.getProjectById(event.getProjectId())
);
}
activeUserSession.addSessionEvent(event);
}
private void acceptChangesInNavigatorTree(WSEventType eventType,
RMResource[] resourceParsedPath,
WebProjectImpl project) {
List<RMResource> rmResourcePath = Arrays.asList(resourceParsedPath);
private void acceptChangesInNavigatorTree(WSEventType eventType, String resourcePath, WebProjectImpl project) {
if (eventType == WSEventType.RM_RESOURCE_CREATED) {
RMEventManager.fireEvent(
new RMEvent(RMEvent.Action.RESOURCE_ADD,
project.getRmProject(),
rmResourcePath)
resourcePath)
);
} else if (eventType == WSEventType.RM_RESOURCE_DELETED) {
RMEventManager.fireEvent(
new RMEvent(RMEvent.Action.RESOURCE_DELETE,
project.getRmProject(),
rmResourcePath)
resourcePath)
);
}
}
@@ -0,0 +1,69 @@
/*
* 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.server.events;
import io.cloudbeaver.model.session.BaseWebSession;
import io.cloudbeaver.service.security.SMUtils;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.websocket.event.permissions.WSSubjectPermissionEvent;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
import java.util.HashSet;
public class WSSubjectPermissionUpdatedEventHandler extends WSDefaultEventHandler<WSSubjectPermissionEvent> {
private static final Log log = Log.getLog(WSSubjectPermissionUpdatedEventHandler.class);
@Override
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSSubjectPermissionEvent event) {
var oldUserPermissions = new HashSet<>(activeUserSession.getUserContext().getUserPermissions());
try {
activeUserSession.getUserContext().refreshSMSession();
} catch (DBException e) {
activeUserSession.addSessionError(e);
log.error("Error refreshing session", e);
}
activeUserSession.refreshUserData();
var newUserPermissions = activeUserSession.getUserContext().getUserPermissions();
boolean shouldUpdateData = !(SMUtils.isRMAdmin(oldUserPermissions) && SMUtils.isRMAdmin(newUserPermissions));
if (shouldUpdateData) {
super.updateSessionData(activeUserSession, event);
}
}
@Override
protected boolean isAcceptableInSession(@NotNull BaseWebSession activeUserSession, @NotNull WSSubjectPermissionEvent event) {
if (!super.isAcceptableInSession(activeUserSession, event)) {
return false;
}
var user = activeUserSession.getUserContext().getUser();
if (user == null) {
return false;
}
var subjectId = event.getSubjectId();
switch (event.getSubjectType()) {
case user:
return CommonUtils.equalObjects(user.getUserId(), subjectId);
case team:
return ArrayUtils.containsIgnoreCase(user.getTeams(), subjectId);
default:
return false;
}
}
}
@@ -33,7 +33,9 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
@@ -71,11 +73,25 @@ public class CBJettyServer {
JettyServer server;
int serverPort = application.getServerPort();
String serverHost = application.getServerHost();
if (CommonUtils.isEmpty(serverHost)) {
server = new JettyServer(serverPort);
Path sslPath = application.getSslConfigurationPath();
boolean sslConfigurationExists = sslPath != null && Files.exists(sslPath);
if (sslConfigurationExists) {
server = new JettyServer();
XmlConfiguration sslConfiguration = new XmlConfiguration(new PathResource(sslPath));
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// method sslConfiguration.configure() does not see the context class of the Loader,
// so we have to configure it manually, then return the old classLoader.
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
sslConfiguration.configure(server);
Thread.currentThread().setContextClassLoader(classLoader);
} else {
server = new JettyServer(
InetSocketAddress.createUnresolved(serverHost, serverPort));
if (CommonUtils.isEmpty(serverHost)) {
server = new JettyServer(serverPort);
} else {
server = new JettyServer(
InetSocketAddress.createUnresolved(serverHost, serverPort));
}
}
{
@@ -112,8 +128,6 @@ public class CBJettyServer {
server.setHandler(servletContextHandler);
var serverConnector = new ServerConnector(server);
server.addConnector(serverConnector);
JettyWebSocketServletContainerInitializer.configure(servletContextHandler,
(context, wsContainer) -> {
wsContainer.setIdleTimeout(Duration.ofMinutes(5));
@@ -205,11 +219,14 @@ public class CBJettyServer {
servletContextHandler.setSessionHandler(sessionHandler);
}
private static class JettyServer extends Server {
public static class JettyServer extends Server {
public JettyServer(int serverPort) {
super(serverPort);
}
public JettyServer() {
super();
}
public JettyServer(InetSocketAddress addr) {
super(addr);
}
@@ -23,7 +23,7 @@ import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
public class SessionStateJob extends PeriodicSystemJob {
private static final Log log = Log.getLog(SessionStateJob.class);
private static final int PERIOD_MS = 60_000; // once per 60 seconds
private static final int PERIOD_MS = 30_000; // once per 30 seconds
public SessionStateJob(@NotNull CBPlatform platform) {
super("Session state sender", platform, PERIOD_MS);
@@ -0,0 +1,114 @@
/*
* 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.server.jobs;
import io.cloudbeaver.model.session.WebSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.exec.DBCException;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.exec.DBCStatement;
import org.jkiss.dbeaver.model.exec.output.DBCOutputSeverity;
import org.jkiss.dbeaver.model.exec.output.DBCOutputWriter;
import org.jkiss.dbeaver.model.exec.output.DBCServerOutputReader;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.websocket.event.WSOutputLogInfo;
import org.jkiss.dbeaver.model.websocket.event.session.WSOutputDBLogEvent;
import org.jkiss.dbeaver.runtime.DBWorkbench;
import java.util.ArrayList;
import java.util.List;
public class SqlOutputLogReaderJob extends AbstractJob {
private static final Log log = Log.getLog(SqlOutputLogReaderJob.class);
@NotNull
private final WebSession webSession;
@NotNull
private final DBCExecutionContext dbcExecutionContext;
@NotNull
private final DBCStatement dbcStatement;
@NotNull
private final DBCServerOutputReader dbcServerOutputReader;
@NotNull
private final String contextInfoId;
public SqlOutputLogReaderJob(@NotNull WebSession webSession,
@NotNull DBCExecutionContext dbcExecutionContext,
@NotNull DBCStatement dbcStatement,
@NotNull DBCServerOutputReader dbcServerOutputReader,
@NotNull String contextInfoId) {
super("Sql log state job");
this.webSession = webSession;
this.dbcExecutionContext = dbcExecutionContext;
this.dbcStatement = dbcStatement;
this.dbcServerOutputReader = dbcServerOutputReader;
this.contextInfoId = contextInfoId;
}
@Override
protected IStatus run(DBRProgressMonitor monitor) {
if (!DBWorkbench.getPlatform().isShuttingDown()) {
try {
if (!dbcStatement.isStatementClosed()) {
dumpOutput(monitor);
schedule(100);
}
} catch (Exception e) {
log.debug("Failed to execute job " + e.getMessage(), e);
}
}
return Status.OK_STATUS;
}
private void dumpOutput(DBRProgressMonitor monitor) {
if (!monitor.isCanceled()) {
if (dbcServerOutputReader.isAsyncOutputReadSupported()) {
try {
if (!dbcStatement.isStatementClosed()) {
List<WSOutputLogInfo> messages = new ArrayList<>();
dbcServerOutputReader.readServerOutput(monitor, dbcExecutionContext, null, dbcStatement, new DBCOutputWriter() {
@Override
public void println(@Nullable DBCOutputSeverity severity, @Nullable String message) {
if (message != null && severity != null) {
messages.add(new WSOutputLogInfo(severity.getName(), message));
}
}
@Override
public void flush() {
messages.clear();
}
});
webSession.addSessionEvent(new WSOutputDBLogEvent(
contextInfoId,
messages,
System.currentTimeMillis()));
}
} catch (DBCException e) {
log.error(e);
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More