From 5e601b14603c2abde54eaf460461dca89afdec01 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Thu, 6 Mar 2025 18:08:04 +0100
Subject: [PATCH] Updated credentials and visibility

Signed-off-by: Martin Weise <martin.weise@tuwien.ac.at>
---
 .../target/create-event-listener.jar          | Bin 10140 -> 10139 bytes
 dbrepo-dashboard-service/Dockerfile           |   1 -
 .../at/tuwien/endpoints/SubsetEndpoint.java   |  18 +++++--
 .../java/at/tuwien/config/GatewayConfig.java  |   1 -
 .../at/tuwien/service/CredentialService.java  |  16 +++++++
 .../service/impl/CredentialServiceImpl.java   |  44 ++++++++++++++++++
 .../database/[database_id]/subset/index.vue   |   6 +--
 .../database/[database_id]/table/index.vue    |   6 +--
 .../database/[database_id]/view/index.vue     |   6 +--
 helm/dbrepo/files/create-event-listener.jar   | Bin 10140 -> 10139 bytes
 10 files changed, 84 insertions(+), 14 deletions(-)
 create mode 100644 dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
 create mode 100644 dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java

diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar
index b117c50b6646de91273c95dc5749cd54868012be..72d17863f14cc38c1fd026dd7e40e56a25fc4318 100644
GIT binary patch
delta 1017
zcmbQ^Kigk8z?+#xgn@yBgW*e0TGZZok39<~3M<ziRuI^muJ-=`KSOWsqGxHZ9j!yt
zSAE^r*qb_Q0$)zh@9&qk9NYMK1$#oG{BODZN``E&FGu1pR$jg_M>R>r-MHOh#m|!Y
zo7rDn*d)FD+A`<k$C8R1e4>Lh?XFAz+v6&_F80_(MWdyG4hx0q4MP&ol{_rCU67G^
z)^^u94I6j9JN4qVFF!B2+I#wD&8>>_UAEDS(#jnQOXBmj*Ic}Gzb5@cev8sy#sB{2
zt`<$)Y<lt9^PqQS)`?#FEAC2eVVc4)>DV+ro1I~SuP>ZlY$NG@@P&>}@r#59yN@1f
zkma+t7FtvL>Cc76IgV>Ld+x7qv9c*o%=vxqJ$sFs6aP<(hw5)O*RT4yW}}$s*UI&;
z{+tc4U&8Zwmu^c|*3N@_S4rLAY2@%+`D_1yjoh;iAFfQbS?F4>v**aUIVow^!y_jp
zP87M>s$~?a_V{APlB=m)RXnOoqLv?3vAq|)^VR8{_f0&CIyUjiE&6@w5;td)UsTh?
z!Y_=VSm0t{;9vm90t3V3EsToHpL^0K-(b{b{?d~+nS)6VOlvZ!g6TjeEihfjWCEtQ
zGI@d3Gclh9)0ddLLE@VeSmrQ+8UNY1Il&BGff_*&V{(t;EHJI9G?^0~_mht*S%O6w
zm8BUMPnK1dQ25-F7R7)Bgy3uehPRHV7$-ku7MYx>%wqyF1TM$Gz`zXWfE4~>WMD`v
z(GT!uWD;S9`*re4WocPyCa_dVX?bR99)^mC%F>L^lm9A10zghhnz3MVql%0+nn@^b
z)JL&;`Q%0wJFq|g%xiP%VqjqSz`($u0awGou%z(|(_}$rt;w9KJYa=Bzgbr4F)%Rb
zFfcGUp(s4UJozEB%j8N`9tDtx|9@)U?a#!(aE+CL!3afR5X<Cz7L&<0p$fVG3I4go
z!N9OifPp~_Md3%b$$ab*lV#O-z#*@rCe8Gpe{w#H`s4yN1I9U%7pl2}C0?pYGu0_h
v?q!mme4j~d@)<=wXc!>!udqkRxnu?ghK&pi48kauNKY<MS7TeR1QG-QIv;BU

delta 1034
zcmbR3KgVA<z?+#xgn@yBgTXy2HEP4{NV}qm!pilB3<UO;FZ(}1-h*lBw&eUK_Ed-T
zfIaz_*QR6ytKAg)S?zq#$f&Q%W7ElfZ>lS2t4hQ!QvTO=?d7qQ938hrgUuW*tn=lJ
zwzcr_?%tfW*m_Hj(j(=hTd!6<_?&b)zHG&xttLEu6ZN(-eVY1X^)fEwuqR^WyzSG>
z?ks$}<xuvM1NE|Bm#&|@EF<UGv&+XUr^(;o;{L`U!q)$F-61L7zh}!?|GH`9)t&f1
zxp;3>N{;iE;+a!^|BZWbi8JfFR4;>S!xFQltnS-FuSAu6Qt@wVG`ISATE<G^$2-I8
z32leh_f=%im$ffbNDdJ9yz_qkf^X+zGcMPC`OP?=<G!<<<Y(h=^{!WIu1Pd^{n`^;
z`fc4x`Ji8wm!CPAZoTu!F_br_-QmZQkiYQ{Zd9KA_i)dpz6%R%MdK2e`)_%<LPw}a
z^v;uwQb)I^PI1#@cve{_?I`L0NF#7^$lP~pb4v@~ne$H4S+r(vdxm~gm15k5$Zm5Z
z9y>-*G;lF6a4>+Qfno9{MkQwVsMN{V8Fj%lJChuk)?iWv(*aCcV7ivc1Wa#X@&eP0
z%xA&$Mdof0y*Zv`4ilL1kByrX%-|8I5d<+NcPq{U(;7;XIpJ|X`G}GwNOY32G~<%V
zGRhJPASnhUAOvR%FuZj<%{ci1v&iHOWu6>#h0G`le={;LB$nt0cr!AIFeCXCu84tw
z3(f|aEW-rWP*Pf+nVN^LZ}J0WX-1dHf0QAiBC8_JSU9;sMMfK+`T8j4ubAARVh8f-
z<bx{GOkbHM3ovU<=1}DUd)VhU%PKtv1_m7l1_md%HU@?zjYpX$KVWv5Tme=1|5NjB
ze<lWoYpe_mMkoq{StjSPm`uI_RmlBM@Xsv{28MM43=Co@3O}(;=4F?dEThH)c8#{0
zG!uis<UAJj$@yvqjB_V1P;&*lY4^GZNg%g?uq}!S^@@`hs+mqcugC@UKO#d5dxV@z
ZW?*30$iToLjG{?qa=yA6+Xf|&AOQM;NrwOc

diff --git a/dbrepo-dashboard-service/Dockerfile b/dbrepo-dashboard-service/Dockerfile
index e4d9d8f505..d5f64a82fb 100644
--- a/dbrepo-dashboard-service/Dockerfile
+++ b/dbrepo-dashboard-service/Dockerfile
@@ -4,6 +4,5 @@ LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at"
 WORKDIR /app
 
 COPY --chown=grafana:grafana ./dashboards /app/dashboards
-COPY --chown=grafana:grafana ./provisioning /etc/grafana/provisioning
 COPY --chown=grafana:grafana ./grafana.ini /etc/grafana/grafana.ini
 COPY --chown=grafana:grafana ./ldap.toml /etc/grafana/ldap.toml
diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
index 7ca50f8aa8..9fee9476c9 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java
@@ -110,7 +110,13 @@ public class SubsetEndpoint extends RestEndpoint {
             QueryNotFoundException, NotAllowedException, MetadataServiceException {
         log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted);
         final DatabaseDto database = cacheService.getDatabase(databaseId);
-        endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
+        if (!database.getIsPublic()) {
+            if (principal == null) {
+                log.error("Failed to list queries: no authentication found");
+                throw new NotAllowedException("Failed to list queries: no authentication found");
+            }
+            endpointValidator.validateOnlyAccess(database, principal, false);
+        }
         final List<QueryDto> queries;
         try {
             queries = subsetService.findAll(database, filterPersisted);
@@ -171,7 +177,13 @@ public class SubsetEndpoint extends RestEndpoint {
         log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId,
                 subsetId, accept, timestamp);
         final DatabaseDto database = cacheService.getDatabase(databaseId);
-        endpointValidator.validateOnlyPrivateSchemaAccess(database, principal);
+        if (!database.getIsPublic()) {
+            if (principal == null) {
+                log.error("Failed to find query: no authentication found");
+                throw new NotAllowedException("Failed to find query: no authentication found");
+            }
+            endpointValidator.validateOnlyAccess(database, principal, false);
+        }
         final QueryDto subset;
         try {
             subset = subsetService.findById(database, subsetId);
@@ -205,7 +217,7 @@ public class SubsetEndpoint extends RestEndpoint {
                         .headers(headers)
                         .body(resource.getResource());
         }
-        throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead");
+        throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': got " + accept + " instead");
     }
 
     @PostMapping
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
index 17bc60b90a..26f181c39d 100644
--- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java
@@ -5,7 +5,6 @@ import at.tuwien.service.CredentialService;
 import lombok.Getter;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
new file mode 100644
index 0000000000..b1c28cf170
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java
@@ -0,0 +1,16 @@
+package at.tuwien.service;
+
+import at.tuwien.api.keycloak.TokenDto;
+
+public interface CredentialService {
+
+    /**
+     * Gets credentials for a user with given id in a database with given id either from the cache (if not expired) or
+     * retrieves them from the Metadata Service.
+     *
+     * @param username The username.
+     * @param password The user password.
+     * @return The credentials.
+     */
+    TokenDto getAccessToken(String username, String password);
+}
diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java
new file mode 100644
index 0000000000..7cf7d1eff4
--- /dev/null
+++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java
@@ -0,0 +1,44 @@
+package at.tuwien.service.impl;
+
+import at.tuwien.api.keycloak.TokenDto;
+import at.tuwien.gateway.KeycloakGateway;
+import at.tuwien.service.CredentialService;
+import com.github.benmanes.caffeine.cache.Cache;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Log4j2
+@Service
+public class CredentialServiceImpl implements CredentialService {
+
+    private final KeycloakGateway keycloakGateway;
+    private final Cache<String, TokenDto> tokenCache;
+
+    @Autowired
+    public CredentialServiceImpl(KeycloakGateway keycloakGateway, Cache<String, TokenDto> tokenCache) {
+        this.tokenCache = tokenCache;
+        this.keycloakGateway = keycloakGateway;
+    }
+
+    @Override
+    public TokenDto getAccessToken(String username, String password) {
+        final TokenDto cacheAccessToken = tokenCache.getIfPresent(username);
+        if (cacheAccessToken != null) {
+            log.trace("found access token for user with username {} in cache", username);
+            return cacheAccessToken;
+        }
+        log.debug("access token for user with username {} not it cache (anymore): request new", username);
+        final TokenDto token = keycloakGateway.obtainUserToken(username, password);
+        tokenCache.put(username, token);
+        return token;
+    }
+
+    /**
+     * Method for test cases to remove all caches.
+     */
+    public void invalidateAll() {
+        tokenCache.invalidateAll();
+    }
+
+}
diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
index d98a8ba2af..d7127d90af 100644
--- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="canView">
     <DatabaseToolbar />
     <SubsetList />
     <v-breadcrumbs :items="items" class="pa-0 mt-2" />
@@ -42,11 +42,11 @@ export default {
     access () {
       return this.cacheStore.getAccess
     },
-    canViewSchema () {
+    canView () {
       if (!this.database) {
         return false
       }
-      if (this.database.is_schema_public) {
+      if (this.database.is_public || this.database.is_schema_public) {
         return true
       }
       if (!this.access) {
diff --git a/dbrepo-ui/pages/database/[database_id]/table/index.vue b/dbrepo-ui/pages/database/[database_id]/table/index.vue
index c2a2b76206..2ff2a96a81 100644
--- a/dbrepo-ui/pages/database/[database_id]/table/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/table/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="canView">
     <DatabaseToolbar />
     <v-window
       v-model="tab">
@@ -51,11 +51,11 @@ export default {
     access () {
       return this.cacheStore.getAccess
     },
-    canViewSchema () {
+    canView () {
       if (!this.database) {
         return false
       }
-      if (this.database.is_schema_public) {
+      if (this.database.is_public || this.database.is_schema_public) {
         return true
       }
       const userService = useUserService()
diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue
index b2a2c17a1a..0e452aaa61 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/index.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div
-    v-if="canViewSchema">
+    v-if="canView">
     <DatabaseToolbar />
     <v-window
       v-model="tab">
@@ -51,11 +51,11 @@ export default {
     access () {
       return this.cacheStore.getAccess
     },
-    canViewSchema () {
+    canView () {
       if (!this.database) {
         return false
       }
-      if (this.database.is_schema_public) {
+      if (this.database.is_public || this.database.is_schema_public) {
         return true
       }
       const userService = useUserService()
diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar
index b117c50b6646de91273c95dc5749cd54868012be..72d17863f14cc38c1fd026dd7e40e56a25fc4318 100644
GIT binary patch
delta 1017
zcmbQ^Kigk8z?+#xgn@yBgW*e0TGZZok39<~3M<ziRuI^muJ-=`KSOWsqGxHZ9j!yt
zSAE^r*qb_Q0$)zh@9&qk9NYMK1$#oG{BODZN``E&FGu1pR$jg_M>R>r-MHOh#m|!Y
zo7rDn*d)FD+A`<k$C8R1e4>Lh?XFAz+v6&_F80_(MWdyG4hx0q4MP&ol{_rCU67G^
z)^^u94I6j9JN4qVFF!B2+I#wD&8>>_UAEDS(#jnQOXBmj*Ic}Gzb5@cev8sy#sB{2
zt`<$)Y<lt9^PqQS)`?#FEAC2eVVc4)>DV+ro1I~SuP>ZlY$NG@@P&>}@r#59yN@1f
zkma+t7FtvL>Cc76IgV>Ld+x7qv9c*o%=vxqJ$sFs6aP<(hw5)O*RT4yW}}$s*UI&;
z{+tc4U&8Zwmu^c|*3N@_S4rLAY2@%+`D_1yjoh;iAFfQbS?F4>v**aUIVow^!y_jp
zP87M>s$~?a_V{APlB=m)RXnOoqLv?3vAq|)^VR8{_f0&CIyUjiE&6@w5;td)UsTh?
z!Y_=VSm0t{;9vm90t3V3EsToHpL^0K-(b{b{?d~+nS)6VOlvZ!g6TjeEihfjWCEtQ
zGI@d3Gclh9)0ddLLE@VeSmrQ+8UNY1Il&BGff_*&V{(t;EHJI9G?^0~_mht*S%O6w
zm8BUMPnK1dQ25-F7R7)Bgy3uehPRHV7$-ku7MYx>%wqyF1TM$Gz`zXWfE4~>WMD`v
z(GT!uWD;S9`*re4WocPyCa_dVX?bR99)^mC%F>L^lm9A10zghhnz3MVql%0+nn@^b
z)JL&;`Q%0wJFq|g%xiP%VqjqSz`($u0awGou%z(|(_}$rt;w9KJYa=Bzgbr4F)%Rb
zFfcGUp(s4UJozEB%j8N`9tDtx|9@)U?a#!(aE+CL!3afR5X<Cz7L&<0p$fVG3I4go
z!N9OifPp~_Md3%b$$ab*lV#O-z#*@rCe8Gpe{w#H`s4yN1I9U%7pl2}C0?pYGu0_h
v?q!mme4j~d@)<=wXc!>!udqkRxnu?ghK&pi48kauNKY<MS7TeR1QG-QIv;BU

delta 1034
zcmbR3KgVA<z?+#xgn@yBgTXy2HEP4{NV}qm!pilB3<UO;FZ(}1-h*lBw&eUK_Ed-T
zfIaz_*QR6ytKAg)S?zq#$f&Q%W7ElfZ>lS2t4hQ!QvTO=?d7qQ938hrgUuW*tn=lJ
zwzcr_?%tfW*m_Hj(j(=hTd!6<_?&b)zHG&xttLEu6ZN(-eVY1X^)fEwuqR^WyzSG>
z?ks$}<xuvM1NE|Bm#&|@EF<UGv&+XUr^(;o;{L`U!q)$F-61L7zh}!?|GH`9)t&f1
zxp;3>N{;iE;+a!^|BZWbi8JfFR4;>S!xFQltnS-FuSAu6Qt@wVG`ISATE<G^$2-I8
z32leh_f=%im$ffbNDdJ9yz_qkf^X+zGcMPC`OP?=<G!<<<Y(h=^{!WIu1Pd^{n`^;
z`fc4x`Ji8wm!CPAZoTu!F_br_-QmZQkiYQ{Zd9KA_i)dpz6%R%MdK2e`)_%<LPw}a
z^v;uwQb)I^PI1#@cve{_?I`L0NF#7^$lP~pb4v@~ne$H4S+r(vdxm~gm15k5$Zm5Z
z9y>-*G;lF6a4>+Qfno9{MkQwVsMN{V8Fj%lJChuk)?iWv(*aCcV7ivc1Wa#X@&eP0
z%xA&$Mdof0y*Zv`4ilL1kByrX%-|8I5d<+NcPq{U(;7;XIpJ|X`G}GwNOY32G~<%V
zGRhJPASnhUAOvR%FuZj<%{ci1v&iHOWu6>#h0G`le={;LB$nt0cr!AIFeCXCu84tw
z3(f|aEW-rWP*Pf+nVN^LZ}J0WX-1dHf0QAiBC8_JSU9;sMMfK+`T8j4ubAARVh8f-
z<bx{GOkbHM3ovU<=1}DUd)VhU%PKtv1_m7l1_md%HU@?zjYpX$KVWv5Tme=1|5NjB
ze<lWoYpe_mMkoq{StjSPm`uI_RmlBM@Xsv{28MM43=Co@3O}(;=4F?dEThH)c8#{0
zG!uis<UAJj$@yvqjB_V1P;&*lY4^GZNg%g?uq}!S^@@`hs+mqcugC@UKO#d5dxV@z
ZW?*30$iToLjG{?qa=yA6+Xf|&AOQM;NrwOc

-- 
GitLab