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