Compare commits

..

94 Commits

Author SHA1 Message Date
Diamantis Tziotzios e8aef281d4 Merge branch 'Development' 2024-02-22 11:09:31 +02:00
Diamantis Tziotzios 00c6978594 no message 2024-02-22 11:07:51 +02:00
Diamantis Tziotzios 3adb518e61 fixes 2024-02-14 22:10:15 +02:00
Konstantina Galouni eb74ef86b9 rich-text-editor.component.ts: Removed "backgroundColor" from toolbarHiddenButtons & added in customClasses "Highlight" option with custom "highlight" class | _type.scss: Added rules for "blockquote" and ".highlight" (added by rich text editor). 2024-02-13 13:23:13 +02:00
Diamantis Tziotzios a1ee9c82bc fixes 2024-01-31 17:55:08 +02:00
Diamantis Tziotzios 5e5bd39313 no message 2024-01-30 13:26:31 +02:00
Diamantis Tziotzios 5e99cef60e default blueprint update 2024-01-24 16:25:46 +02:00
Diamantis Tziotzios cc7edc2f49 final fixes for #9384 #9153 #9409 #9420 2024-01-24 16:17:06 +02:00
Diamantis Tziotzios a1849c64ca Merge branch 'Development' of https://code-repo.d4science.org/MaDgiK-CITE/argos into Development
# Conflicts:
#	dmp-frontend/src/app/ui/dmp/dmp-editor-blueprint/dmp-editor-blueprint.component.ts
2024-01-24 14:48:38 +02:00
Diamantis Tziotzios 192220161b fixes 2024-01-24 14:47:37 +02:00
George Kalampokis 87758c3e9a Fix various issues with adding/removing Dataset Templates 2024-01-24 14:31:46 +02:00
Diamantis Tziotzios 83342f5afa docx template update 2024-01-17 17:49:52 +02:00
Diamantis Tziotzios 65cdb3b6ea fixes for #9384 #9153 #9162 #9265 2024-01-17 16:50:12 +02:00
Diamantis Tziotzios 536ba9b900 Fixes for #9152 #9153 #9162 #9265 #9266 #9311 #9312 2024-01-09 09:42:58 +02:00
Alexandros Mandilaras 6bd3302788 sql script fix 2023-11-23 15:16:11 +02:00
Diamantis Tziotzios 4970f5812f fix issues #9152 #9153 #9204 #9208 2023-11-23 13:15:50 +02:00
Diamantis Tziotzios 9fed92dbcb fixes for #9109 #9146 #9148 #9149 #9152 #9153 #9156 #9157 #9158 #9160 #9162 #9163 #9164 #9166 2023-11-03 13:24:01 +02:00
Diamantis Tziotzios 44dab9c19a gitignore changes 2023-11-01 09:41:22 +02:00
Alexandros Mandilaras 54f911d826 typo fixes in greek and english translations 2023-10-23 10:12:17 +03:00
Diamantis Tziotzios 9879050eab cleanup 2023-10-19 17:28:36 +03:00
Diamantis Tziotzios 8a41a7dcd9 Fixes for #9033 #9107 #9105 #9105 2023-10-19 17:27:37 +03:00
Diamantis Tziotzios d60cc144d5 #9033 Description Templates - change "Other" API label to "Custom" 2023-10-18 16:10:12 +03:00
Georgios Kakaletris 9c37e5a073 Update 'README.md' 2023-10-18 12:31:03 +02:00
Georgios Kakaletris 444c1aacb1 Update 'README.md' 2023-10-18 12:27:40 +02:00
Diamantis Tziotzios 59d7383947 added basque contributors at static pages 2023-10-17 13:48:50 +03:00
Diamantis Tziotzios 6caa1af134 Added Basque language 2023-10-16 18:21:22 +03:00
George Kalampokis 74a6019a72 Fix some styling and compilation errors 2023-10-10 12:10:52 +03:00
George Kalampokis 5c903c0f48 Add missing files 2023-10-10 12:04:06 +03:00
George Kalampokis ec8f6a6d48 Add Authentication support for the remote fetcher and rework dataset template's autocomplete sources 2023-10-10 12:03:59 +03:00
Bernaldo Mihasi ecd86f413a show prefilling pop up if only at least one dataset profile has enabled prefilling property 2023-10-06 11:22:23 +03:00
Bernaldo Mihasi c238615b50 add enable prefilling property in description templates 2023-10-06 09:36:35 +03:00
Bernaldo Mihasi 10d0f1fb0e make word list labels and delete icons in finalized description templates disabled 2023-10-05 17:47:00 +03:00
Bernaldo Mihasi 846405435c bug fixes 2023-10-05 09:33:28 +03:00
Bernaldo Mihasi dfc9e14003 update i18n 2023-10-04 17:03:50 +03:00
Bernaldo Mihasi bc1894586b 1) update dmp blueprint listing table view, 2) create clone functionality for dmp blueprints, 3) section description is not required in editor, 4) in the deletion of a dmp blueprint check if any dmps are accosiated with it 2023-10-04 09:43:16 +03:00
Bernaldo Mihasi 2bf0a857bc bug fixes: 1) when creating description template type check only for non deleted types, 2) dmp docx/pdf export: check if system fields exist 3) when creating/updating dmp check if value for extra fields is set, 4) when unchecking the 'Description Templates' checkbox in the blueprint editor, clear any templates selected 2023-10-02 13:57:00 +03:00
Bernaldo Mihasi 3d10e8ad28 add type attribute in xml import/export of a description template 2023-10-02 10:14:14 +03:00
Bernaldo Mihasi 53b61853e1 bug fixes 2023-10-02 09:34:58 +03:00
Bernaldo Mihasi d644b1dc91 [wip] dmp xml upload changes, including section and extra fields information 2023-10-02 09:34:21 +03:00
Diamantis Tziotzios 50c96ef821 Merge branch 'Development' 2023-06-20 09:39:15 +03:00
Konstantina Galouni 0adc7044ab h2020.docx: [Bug fix] Updated image of Argos in h2020.docx DMP template | DataManagementPlanManager.java & DatasetManager.java: Added parameter "isDataset" in fillFirstPage() | WordBuilder.java: [Bug fix] Added parameter isDataset in fillFirstPage() and added some checks in description.
(cherry picked from commit c9b4b35e39)
2023-05-09 10:33:44 +03:00
Konstantina Galouni 13e62fd409 h2020.docx & WordBuilder.java: Updated h2020.docx DMP template and added export of DMP description.
(cherry picked from commit 28c1c9b71d)
2023-03-14 10:23:35 +02:00
Diamantis Tziotzios 7185b5d117 Merge commit '180e02c829a8fb35056124d5afdbec3835a94b62' 2023-02-28 16:08:32 +02:00
George Kalampokis 5f131b9823 Remove thread sleeps when trying to load config files and removed principal from Exception Handling Controller 2022-12-06 14:34:11 +02:00
Diamantis Tziotzios 93320f7c94 Merge branch 'Development' 2022-11-22 15:03:08 +02:00
Diamantis Tziotzios 876d99ce38 Merge commit '18dcabbac2599d35246f91204efbb25238106565' 2022-11-03 14:20:16 +02:00
George Kalampokis 7a71110033 Fix critical issue with open file handle leak on user guide folder
(cherry picked from commit fa723c07ae)
2022-07-28 17:14:13 +03:00
Diamantis Tziotzios 14c267c97e Merge branch 'Development'
# Conflicts:
#	dmp-backend/web/src/main/resources/config/application-production.properties
2022-05-13 11:58:34 +03:00
Diamantis Tziotzios b04b35d62b Merge branch 'Development'
# Conflicts:
#	dmp-backend/web/src/main/resources/RDACommonStandards.txt
2022-02-25 12:19:29 +02:00
Diamantis Tziotzios 7a8375b988 Merge commit '2cb985c23c4ceda99efc78bcc8e77b3eceeb0bcf'
# Conflicts:
#	dmp-backend/elastic/src/main/java/eu/eudat/elastic/criteria/DatasetCriteria.java
#	dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dataset.java
#	dmp-backend/elastic/src/main/java/eu/eudat/elastic/entities/Dmp.java
#	dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/DatasetRepository.java
#	dmp-backend/elastic/src/main/java/eu/eudat/elastic/repository/DmpRepository.java
#	dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java
#	dmp-backend/web/src/main/java/eu/eudat/logic/mapper/elastic/criteria/DmpCriteriaMapper.java
#	dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java
#	dmp-backend/web/src/main/java/eu/eudat/models/data/listingmodels/DataManagementPlanListingModel.java
2021-12-09 12:18:39 +02:00
Diamantis Tziotzios 895dbcf098 Revert "user guide path fix"
This reverts commit bd15b1e2c7.
2021-07-07 20:39:41 +03:00
Diamantis Tziotzios bd15b1e2c7 user guide path fix 2021-07-07 20:39:22 +03:00
George Kalampokis faabd343a9 Improve error handling
(cherry picked from commit d5cd90814a)
2021-07-06 13:41:09 +03:00
George Kalampokis e5a929f259 Fix issues with xml import and issues with zenodo deposit
(cherry picked from commit efe177f0b1)
2021-07-06 13:40:15 +03:00
George Kalampokis d1fc10854c Fix issue with zenodo depositions
(cherry picked from commit c57e10a033)
2021-07-06 12:15:49 +03:00
George Kalampokis 2537923dc0 Fix various critical issues
(cherry picked from commit 244bfa5c54)
2021-07-05 11:10:11 +03:00
George Kalampokis c1adbe283a Improvements over MS Word Document export
(cherry picked from commit 4e3b98f1ff)
2021-06-30 18:48:20 +03:00
George Kalampokis 1c365a191e Minor Update
(cherry picked from commit 295750684f)
2021-06-30 18:48:13 +03:00
Kristian Ntavidi 82c5586067 Dataset and dmp overview fix.
* Fix edit issue when multiple users have ownership of the same dmp/dataset.

(cherry picked from commit fd9d35aad3)
2021-06-30 13:38:53 +03:00
George Kalampokis 04f230dff1 Fix critical issue with dataset's copy dropdown
(cherry picked from commit d1e3aae36d)
2021-06-30 12:52:32 +03:00
George Kalampokis 72d88d9db4 Fix listing issues and improve elastic query
(cherry picked from commit dcd7f24cac)
2021-06-29 14:25:38 +03:00
George Kalampokis 143a4c0214 Reduce severity
(cherry picked from commit 03b7699973)
2021-06-25 19:31:45 +03:00
George Kalampokis e7e5ed02b3 Add query db fallback for DMPs
(cherry picked from commit d1df83f689)
2021-06-25 19:28:29 +03:00
George Kalampokis b5fcc5971e Fix various library issues with postgres and elastic
(cherry picked from commit 4a4042d621)
2021-06-25 12:46:09 +03:00
Diamantis Tziotzios c16c35225f Merge branch 'Development' 2021-06-25 08:50:27 +03:00
Diamantis Tziotzios f5d266554b Merge commit 'ca91c14114b8994d41fdf2b97fc6d1a4d82ffa4e' 2021-05-19 14:22:47 +03:00
Diamantis Tziotzios db31597fc0 Merge branch 'Development' 2020-10-07 10:58:45 +03:00
Diamantis Tziotzios 9f5054668e Merge branch 'Development'
* Development: (72 commits)
  splash screen fixes
  splash spell error fix
  Properly remove associate Collaborators from a DMP
  splash changes
  Fixed issue with DMP filter on public datasets
  Fixed issue when using the copy dataset dialog
  Minor styling improvement over DMP Overview
  Code clean up
  Add support for newer versions of java (11) (expirimental)
  Add Zenodo file visibility field for DMP (ref #274)
  Fixed issue not passing DMP Extra Properties on clones and new Versions
  Add DMP Zenodo license field (ref #274)
  more splash screen changes
  Allow splash to send contact emails
  splash screen changes
  Hide Uri field on Dataset Editor (ref #275)
  When logging in remove the cookie consent popup
  Fixed minor issues with RDA Mapping
  Add currency field type for dataset templates
  Add DMP language a placeholder on UI
  ...

# Conflicts:
#	dmp-backend/web/src/main/resources/RDACommonStandards.txt
#	dmp-backend/web/src/main/resources/config/application-production.properties
2020-07-03 11:00:07 +03:00
George Kalampokis 38986ef67b no message 2020-06-16 17:58:31 +03:00
Diamantis Tziotzios bff260b85b config file changes 2020-06-16 17:54:50 +03:00
George Kalampokis 9519300dc4 Removed deprecated configurations and added additional RDA Common Standards for dataset Templates
(cherry picked from commit 5b0a66ce06)
2020-05-29 12:07:59 +03:00
George Kalampokis 9373d3e038 Fixed logback paths
(cherry picked from commit 33ec8b81c0)
2020-05-20 15:39:27 +03:00
dtziotzios d971f02a94 Merge branch 'Development'
# Conflicts:
#	dmp-backend/web/src/main/java/eu/eudat/controllers/DMPs.java
#	dmp-backend/web/src/main/java/eu/eudat/logic/managers/DataManagementPlanManager.java
2020-05-13 17:29:52 +03:00
Georgios Kakaletris d3915e26e7 Update LICENSE 2020-05-09 00:03:50 +02:00
George Kalampokis c028aad615 Fixed and improved file export system
(cherry picked from commit 71ccd76896)
2020-04-02 18:44:40 +03:00
Diamantis Tziotzios 4ee39074a3 Merge commit '8ca2b912d40ece8bf0fbcda5c49f1ef7f5f6fdfd' 2020-04-02 13:33:08 +03:00
Diamantis Tziotzios 1b4952a909 Merge branch 'Development' 2020-01-31 18:26:27 +02:00
Diamantis Tziotzios 3ada5a0d3d Merge branch 'Development' 2019-11-26 11:41:02 +02:00
Diamantis Tziotzios 63ee865dd9 Merge commit 'c8358f22dd5d108b7f270f97724d6bab1582c2c5' 2019-11-22 18:08:55 +02:00
Diamantis Tziotzios 2a52138124 Merge branch 'Development' 2019-09-17 18:47:39 +03:00
Diamantis Tziotzios 7cf64c18f2 Merge branch 'Development' 2019-09-17 11:31:58 +03:00
Diamantis Tziotzios 71d317bab7 license file 2019-06-19 08:59:52 +02:00
Ioannis Kalyvas cd8b3448f5 Merge branch 'Development' of https://gitlab.eudat.eu/dmp/OpenAIRE-EUDAT-DMP-service-pilot 2018-06-28 12:39:39 +03:00
Ioannis Kalyvas c3d4cb6fdd no message 2018-06-28 12:33:43 +03:00
Ioannis Kalyvas b0ccac191f no message 2018-03-06 17:33:55 +02:00
Ioannis Kalyvas 3b1f37ef22 no message 2018-03-06 17:27:24 +02:00
Ioannis Kalyvas b8e040ee94 Merge branch 'master' of https://gitlab.eudat.eu/dmp/OpenAIRE-EUDAT-DMP-service-pilot
# Conflicts:
#	dmp-backend/src/main/java/eu/eudat/helpers/Transformers.java
2018-03-06 17:21:46 +02:00
Ioannis Kalyvas 50444a0b73 Merge branch 'Development' of https://gitlab.eudat.eu/dmp/OpenAIRE-EUDAT-DMP-service-pilot
# Conflicts:
#	dmp-backend/src/main/java/eu/eudat/helpers/Transformers.java
#	dmp-frontend/src/index.html
2018-03-06 17:02:13 +02:00
Diamantis Tziotzios 85bdb7fad1 Merge branch 'Development'
# Conflicts:
#	dmp-backend/src/main/java/eu/eudat/helpers/Transformers.java
2018-02-12 10:23:41 +02:00
annabakouli b2e49fbb8a no message 2018-01-18 12:55:35 +02:00
Diamantis Tziotzios bfc6b63067 Merge branch 'Development'
# Conflicts:
#	dmp-backend/src/main/java/rest/entities/DMPs.java
#	dmp-backend/src/main/java/rest/entities/DataRepositories.java
#	dmp-backend/src/main/java/rest/entities/DatasetProfiles.java
#	dmp-backend/src/main/java/rest/entities/Datasets.java
#	dmp-backend/src/main/java/rest/entities/DmpProfiles.java
#	dmp-backend/src/main/java/rest/entities/Organisations.java
#	dmp-backend/src/main/java/rest/entities/Projects.java
#	dmp-backend/src/main/java/rest/entities/Registries.java
#	dmp-backend/src/main/java/rest/entities/Researchers.java
#	dmp-backend/src/main/java/rest/entities/Services.java
#	dmp-backend/src/main/java/rest/entities/Users.java
#	dmp-frontend/src/app/app.component.ts
#	dmp-frontend/src/app/login/googgle-sign-in/googgle-sign-in.component.ts
#	dmp-frontend/src/assets/custom.js
#	dmp-frontend/src/index.html
2018-01-18 12:45:51 +02:00
Nikolaos Laskaris 9941c96dc2 Minor edits 2017-11-27 16:08:13 +02:00
Nikolaos Laskaris 06272c79da -- 2017-11-23 17:34:35 +02:00
Nikolaos Laskaris a00eec68d8 fixed glitches of google-sign-in component 2017-11-23 13:13:20 +02:00
6150 changed files with 233310 additions and 427680 deletions

5
.env Normal file
View File

@ -0,0 +1,5 @@
PROFILE=docker
# Version of Elastic products
ELK_VERSION=7.17.4
STACK_VERSION=7.17.4

65
.gitignore vendored
View File

@ -1,32 +1,32 @@
dmp-frontend/dist.7z
.idea/
*.iml
backend/src/main/ui-resources/static/vendor.bundle.js.map
backend/src/main/ui-resources/static/vendor.bundle.js
backend/src/main/ui-resources/static/unauthorized.module.chunk.js.map
backend/src/main/ui-resources/static/unauthorized.module.chunk.js
backend/src/main/ui-resources/static/styles.bundle.js.map
backend/src/main/ui-resources/static/styles.bundle.js
backend/src/main/ui-resources/static/polyfills.bundle.js.map
backend/src/main/ui-resources/static/polyfills.bundle.js
backend/src/main/ui-resources/static/main.bundle.js.map
backend/src/main/ui-resources/static/main.bundle.js
backend/src/main/ui-resources/static/lang/en.json
backend/src/main/ui-resources/static/inline.bundle.js.map
backend/src/main/ui-resources/static/inline.bundle.js
backend/src/main/ui-resources/static/index.html
backend/src/main/ui-resources/static/favicon.ico
backend/src/main/ui-resources/static/assets/lang/en.json
dmp-backend/src/main/ui-resources/static/vendor.bundle.js.map
dmp-backend/src/main/ui-resources/static/vendor.bundle.js
dmp-backend/src/main/ui-resources/static/unauthorized.module.chunk.js.map
dmp-backend/src/main/ui-resources/static/unauthorized.module.chunk.js
dmp-backend/src/main/ui-resources/static/styles.bundle.js.map
dmp-backend/src/main/ui-resources/static/styles.bundle.js
dmp-backend/src/main/ui-resources/static/polyfills.bundle.js.map
dmp-backend/src/main/ui-resources/static/polyfills.bundle.js
dmp-backend/src/main/ui-resources/static/main.bundle.js.map
dmp-backend/src/main/ui-resources/static/main.bundle.js
dmp-backend/src/main/ui-resources/static/lang/en.json
dmp-backend/src/main/ui-resources/static/inline.bundle.js.map
dmp-backend/src/main/ui-resources/static/inline.bundle.js
dmp-backend/src/main/ui-resources/static/index.html
dmp-backend/src/main/ui-resources/static/favicon.ico
dmp-backend/src/main/ui-resources/static/assets/lang/en.json
dmp-frontend/new 3.xml
backend/src/main/ui-resources/static/
backend/web/target/
dmp-backend/src/main/ui-resources/static/
dmp-backend/web/target/
*.class
backend/web/src/main/ui-resources/static/
backend/data/target/data-1.0-SNAPSHOT.jar
backend/data/target/
backend/queryable/target/
backend/elastic/target/
backend/queryengine/target/
dmp-backend/web/src/main/ui-resources/static/
dmp-backend/data/target/data-1.0-SNAPSHOT.jar
dmp-backend/data/target/
dmp-backend/queryable/target/
dmp-backend/elastic/target/
dmp-backend/queryengine/target/
*.tar
*.gz
final/
@ -38,7 +38,7 @@ dmp-frontend/.vscode/
dmp-frontend/package-lock.json
backend/logging/target/
dmp-backend/logging/target/
ELK.Docker/shared/data-elk/
# Eclipse
@ -46,15 +46,6 @@ ELK.Docker/shared/data-elk/
.settings/
bin/
*.classpath
.run
openDMP/backend/uploads/
openDMP/backend/tmp/
logs/
backend/web/src/main/resources/certificates/
/storage/
backend/target/classes/
backend/core/target/maven-archiver/
backend/node_modules/.yarn-integrity
dmp-frontend/.nx/
notification-service/notification-web/src/main/resources/config/app.env
backend/web/src/main/resources/config/app.env
openDMP/dmp-backend/uploads/
openDMP/dmp-backend/tmp/
dmp-frontend/.angular/

3
ELK.Docker/.env Normal file
View File

@ -0,0 +1,3 @@
ELK_VERSION=7.6.0
# Leave blank to use the "basic" image flavours, which include X-Pack.
# see https://www.elastic.co/subscriptions

2
ELK.Docker/.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Declare files that will always have LF line endings on checkout.
*.sh text eol=lf

21
ELK.Docker/LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Anthony Lapenna
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
ELK.Docker/README.md Normal file
View File

@ -0,0 +1,4 @@
Init default users and retrieve passwords
1) connect to elasticsearch container with docker exec -it elastichsearch /bin/bash
2) run ./bin/elasticsearch-setup-passwords auto >./data/passwords.txt (press y and enter when the console shows nothing)

View File

@ -0,0 +1,87 @@
version: '2.4'
services:
elasticsearch:
user: 1002:1002 #develuser
restart: unless-stopped
mem_limit: 2048m
environment:
- cluster.name=open-dmp-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xmx1024m -Xms1024m"
- xpack.license.self_generated.type=basic
- xpack.monitoring.collection.enabled=true
- xpack.security.enabled=true
ulimits:
nproc: 65535
memlock:
soft: -1
hard: -1
volumes:
- ./shared/config-elk/elasticsearch/config/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties:ro
- ./shared/config-elk/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
- ./shared/data-elk/elasticsearch-01-data:/usr/share/elasticsearch/data
- ./shared/data-elk/elasticsearch-01-log:/usr/share/elasticsearch/logs
#ports:
# - 51056:9200
# - 51057:9300
ports:
- "9200:9200"
expose:
- "9300"
networks:
open-dmp-elk-network:
logstash:
# user: 1002:1002 #develuser
volumes:
- ./shared/config-elk/logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
- ./shared/config-elk/logstash/config/pipelines.yml:/usr/share/logstash/config/pipelines.yml:ro
- ./shared/config-elk/logstash/config/log4j2.properties:/usr/share/logstash/config/log4j2.properties:ro
- ./shared/config-elk/logstash/pipeline:/usr/share/logstash/pipeline:ro
- ./shared/config-elk/logstash/logstash/templates:/usr/share/logstash/templates
- ./shared/data-elk/logstash-log:/usr/share/logstash/logs
- ./shared/data-elk/logstash-queue:/usr/share/logstash/queue
- ./shared/data-elk/logstash-dead_letter_queue:/usr/share/logstash/dead_letter_queue
expose:
- "31311"
- "31312"
restart: on-failure
mem_limit: 2048m
environment:
- LS_JAVA_OPTS=-Xmx1024m -Xms1024m
- xpack.license.self_generated.type=basic
- xpack.security.enabled=true
networks:
open-dmp-elk-network:
kibana:
# user: 1002:1002 #develuser
mem_limit: 512m
environment:
- xpack.license.self_generated.type=basic
- xpack.security.enabled=true
volumes:
- ./shared/config-elk/kibana/config:/usr/share/kibana/config:ro
#- ./shared/config-elk/kibana/certificates:/usr/share/kibana/certificates
restart: unless-stopped
ports:
- "51058:5601"
networks:
- open-dmp-elk-network
filebeat:
restart: unless-stopped
mem_limit: 256m
#command: [ "-e=false" ] # to overwrite the -e that disables logging to file!
volumes:
- ./shared/config-elk/filebeat/config/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- ~/openDMP/logs:/usr/share/filebeat/log_data/dmp/
- ./shared/data-elk/filebeat-log:/usr/share/filebeat/logs
- ./shared/data-elk/filebeat-data:/usr/share/filebeat/data #For windows if we mount the data directory we get "Writing of registry returned error: sync /usr/share/filebeat/data/registry/filebeat: invalid argument."
networks:
- open-dmp-elk-network
networks:
open-dmp-elk-network:

View File

@ -0,0 +1,43 @@
version: '2.4'
services:
elasticsearch:
image: ${DOCKER_REGISTRY}elasticsearch
container_name: elasticsearch
build:
context: elasticsearch/
args:
ELK_VERSION: $ELK_VERSION
healthcheck:
# test: curl --cacert /usr/share/elasticsearch/config/certificates/ca/ca.crt -s https://localhost:9200 >/dev/null; if [[ $$? == 52 ]]; then echo 0; else echo 1; fi
interval: 30s
timeout: 10s
retries: 5
logstash:
image: ${DOCKER_REGISTRY}logstash
container_name: logstash
build:
context: logstash/
args:
ELK_VERSION: $ELK_VERSION
depends_on:
- elasticsearch
kibana:
image: ${DOCKER_REGISTRY}kibana
build:
context: kibana/
args:
ELK_VERSION: $ELK_VERSION
depends_on:
- elasticsearch
filebeat:
image: ${DOCKER_REGISTRY}filebeat
build:
context: filebeat/
args:
ELK_VERSION: $ELK_VERSION
depends_on:
- logstash

View File

@ -0,0 +1,22 @@
ARG ELK_VERSION
# https://github.com/elastic/elasticsearch-docker
FROM docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION}
RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-icu && \
/usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-phonetic
RUN groupmod -g 1002 elasticsearch
RUN usermod -u 1002 -g 1002 elasticsearch
RUN chown -R elasticsearch /usr/share/elasticsearch
RUN sed -i -e 's/--userspec=1000/--userspec=1002/g' \
-e 's/UID 1000/UID 1002/' \
-e 's/chown -R 1000/chown -R 1002/' /usr/local/bin/docker-entrypoint.sh
RUN chown elasticsearch /usr/local/bin/docker-entrypoint.sh
ENV JAVA_HOME /usr/share/elasticsearch/jdk
# RUN mkdir /usr/share/elasticsearch/custom-plugins
# COPY plugins/elasticsearch-analysis-greeklish-7.5.1.zip /usr/share/elasticsearch/custom-plugins/elasticsearch-analysis-greeklish-7.5.1.zip
# RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install file:///usr/share/elasticsearch/custom-plugins/elasticsearch-analysis-greeklish-7.5.1.zip

View File

@ -0,0 +1,15 @@
ARG ELK_VERSION
FROM docker.elastic.co/beats/filebeat:${ELK_VERSION}
# USER root
# RUN groupmod -g 1002 filebeat
# RUN usermod -u 1002 -g 1002 filebeat
# RUN chown -R filebeat /usr/share/filebeat
# RUN sed -i -e 's/--userspec=1000/--userspec=1002/g' \
# -e 's/UID 1000/UID 1002/' \
# -e 's/chown -R 1000/chown -R 1002/' /usr/local/bin/docker-entrypoint
# RUN chown filebeat /usr/local/bin/docker-entrypoint
# USER 1002:1002

View File

@ -0,0 +1,15 @@
ARG ELK_VERSION
# https://github.com/elastic/kibana-docker
FROM docker.elastic.co/kibana/kibana:${ELK_VERSION}
# USER root
# RUN groupmod -g 1002 kibana
# RUN usermod -g 1002 root
# RUN usermod -u 1002 -g 1002 kibana
# RUN chown -R kibana /usr/share/kibana
# USER 1002:1002
# Add your kibana plugins setup here
# Example: RUN kibana-plugin install <name|url>

View File

@ -0,0 +1,20 @@
ARG ELK_VERSION
# https://github.com/elastic/logstash-docker
FROM docker.elastic.co/logstash/logstash:${ELK_VERSION}
# USER root
# RUN groupmod -g 1002 logstash
# RUN usermod -u 1002 -g 1002 logstash
# RUN chown -R logstash /usr/share/logstash
# RUN sed -i -e 's/--userspec=1000/--userspec=1002/g' \
# -e 's/UID 1000/UID 1002/' \
# -e 's/chown -R 1000/chown -R 1002/' /usr/local/bin/docker-entrypoint
# RUN chown logstash /usr/local/bin/docker-entrypoint
# USER 1002:1002
# Add your logstash plugins setup here
# Example: RUN logstash-plugin install logstash-filter-json
RUN logstash-plugin update logstash-input-beats
RUN logstash-plugin update logstash-filter-grok

3
ELK.Docker/old/.env Normal file
View File

@ -0,0 +1,3 @@
TAG=6.3.1
ELASTIC_VERSION=6.3.1
ELASTIC_PASSWORD=changeme

1
ELK.Docker/old/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
**/*~

View File

@ -0,0 +1,7 @@
---
language: python
python: ['3.5']
script: make
sudo: required
services: ['docker']

201
ELK.Docker/old/LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

30
ELK.Docker/old/Makefile Normal file
View File

@ -0,0 +1,30 @@
SHELL=/bin/bash
ifndef ELASTIC_VERSION
ELASTIC_VERSION := $(shell awk 'BEGIN { FS = "[= ]" } /^ELASTIC_VERSION=/ { print $$2 }' .env)
endif
export ELASTIC_VERSION
ifndef GIT_BRANCH
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
endif
TARGETS := apm-server elasticsearch logstash kibana beats
images: $(TARGETS)
push: $(TARGETS:%=%-push)
clean: $(TARGETS:%=%-clean)
$(TARGETS): $(TARGETS:%=%-checkout)
(cd stack/$@ && make)
$(TARGETS:%=%-push): $(TARGETS:%=%-checkout)
(cd stack/$(@:%-push=%) && make push)
$(TARGETS:%=%-checkout):
test -d stack/$(@:%-checkout=%) || \
git clone https://github.com/elastic/$(@:%-checkout=%)-docker.git stack/$(@:%-checkout=%)
(cd stack/$(@:%-checkout=%) && git fetch && git reset --hard && git checkout origin/$(GIT_BRANCH))
$(TARGETS:%=%-clean):
rm -rf stack/$(@:%-clean=%)

25
ELK.Docker/old/README.md Normal file
View File

@ -0,0 +1,25 @@
# stack-docker
This example Docker Compose configuration demonstrates many components of the
Elastic Stack, all running on a single machine under Docker.
## Prerequisites
- Docker and Compose. Windows and Mac users get Compose installed automatically
with Docker. Linux users can:
```
pip install docker-compose
```
- At least 4GiB of RAM for the containers. Windows and Mac users _must_
configure their Docker virtual machine to have more than the default 2 GiB of
RAM:
![Docker VM memory settings](screenshots/docker-vm-memory-settings.png)
## Starting the stack
Try `docker-compose up` to create a demonstration Elastic Stack with
Elasticsearch, Kibana, Logstash, Auditbeat, Metricbeat, Filebeat, Packetbeat,
and Heartbeat.
Point a browser at [`http://localhost:5601`](http://localhost:5601) to see the results.
Log in with `elastic` / `changeme`.

View File

@ -0,0 +1,28 @@
input {
http {
port => 31311 # default: 8080
}
}
filter {
grok{
match => { "message" => "%{GREEDYDATA:request}"}
}
json{
source => "request"
target => "parsed"
}
split{
field=>"entries"
}
}
output {
elasticsearch {
hosts => [ 'elasticsearch' ]
user => 'elastic'
password => 'changeme'
index => "data-management-plan-%{[entries][indexType]}-%{+YYYY.MM.dd}"
}
}

View File

@ -0,0 +1,171 @@
---
version: '3'
services:
# The environment variable "TAG" is used throughout this file to
# specify the version of the images to run. The default is set in the
# '.env' file in this folder. It can be overridden with any normal
# technique for setting environment variables, for example:
#
# TAG=6.0.0-beta1 docker-compose up
#
# REF: https://docs.docker.com/compose/compose-file/#variable-substitution
#
# Also be sure to set the ELASTIC_VERSION variable. For released versions,
# ${TAG} and ${ELASTIC_VERSION} will be identical, but for pre-release
# versions, ${TAG} might contain an extra build identifier, like
# "6.0.0-beta1-3eab5b40", so a full invocation might look like:
#
# ELASTIC_VERSION=6.0.0-beta1 TAG=6.0.0-beta1-3eab5b40 docker-compose up
#
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${TAG}
container_name: elasticsearch
#volumes:
# - esdata:/usr/share/elasticsearch/data
environment: ['http.host=0.0.0.0', 'transport.host=127.0.0.1', 'ELASTIC_PASSWORD=${ELASTIC_PASSWORD}']
ports: ['0.0.0.0:9200:9200']
networks: ['stack']
kibana:
image: docker.elastic.co/kibana/kibana:${TAG}
container_name: kibana
ports: ['0.0.0.0:5601:5601']
networks: ['stack']
depends_on: ['elasticsearch']
logstash:
image: docker.elastic.co/logstash/logstash:${TAG}
container_name: logstash
# Provide a simple pipeline configuration for Logstash with a bind-mounted file.
volumes:
- ./config/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports: ['0.0.0.0:31311:31311']
networks: ['stack']
depends_on: ['elasticsearch', 'setup_logstash']
filebeat:
image: docker.elastic.co/beats/filebeat:${TAG}
container_name: filebeat
command: -e -E 'output.elasticsearch.password=${ELASTIC_PASSWORD}'
# If the host system has logs at "/var/log", mount them at "/mnt/log"
# inside the container, where Filebeat can find them.
# volumes: ['/var/log:/mnt/log:ro']
networks: ['stack']
depends_on: ['elasticsearch', 'setup_filebeat']
heartbeat:
image: docker.elastic.co/beats/heartbeat:${TAG}
container_name: heartbeat
command: -e -E 'output.elasticsearch.password=${ELASTIC_PASSWORD}'
networks: ['stack']
depends_on: ['elasticsearch', 'setup_heartbeat']
# Run a short-lived container to set up Logstash.
setup_logstash:
image: centos:7
container_name: setup_logstash
volumes: ['./scripts/setup-logstash.sh:/usr/local/bin/setup-logstash.sh:ro']
# The script may have CR/LF line endings if using Docker for Windows, so
# make sure that they don't confuse Bash.
command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-logstash.sh | tr -d "\r" | bash']
environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}']
networks: ['stack']
depends_on: ['elasticsearch']
setup_kibana:
image: centos:7
container_name: setup_kibana
volumes: ['./scripts/setup-kibana.sh:/usr/local/bin/setup-kibana.sh:ro']
command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-kibana.sh | tr -d "\r" | bash']
environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}']
networks: ['stack']
depends_on: ['elasticsearch']
setup_filebeat:
image: docker.elastic.co/beats/filebeat:${TAG}
container_name: setup_filebeat
volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro']
command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s filebeat']
environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}']
networks: ['stack']
depends_on: ['kibana']
setup_heartbeat:
image: docker.elastic.co/beats/heartbeat:${TAG}
container_name: setup_heartbeat
volumes: ['./scripts/setup-beat.sh:/usr/local/bin/setup-beat.sh:ro']
command: ['/bin/bash', '-c', 'cat /usr/local/bin/setup-beat.sh | tr -d "\r" | bash -s heartbeat']
environment: ['ELASTIC_PASSWORD=${ELASTIC_PASSWORD}']
networks: ['stack']
depends_on: ['kibana']
##########################DOCSBOX######################################################################
# web:
# restart: always
# build: ./docsbox-master/docsbox
# expose:
# - "8000"
# links:
# - redis:redis
# volumes:
# - docsbox:/home/docsbox
# - media:/home/docsbox/media
# command: gunicorn -b :8000 docsbox:app
# networks: ['stack']
#
# rqworker:
# restart: always
# build: ./docsbox-master/docsbox
# links:
# - redis:redis
# volumes:
# - web
# command: rq worker -c docsbox.settings
# networks: ['stack']
#
# rqscheduler:
# restart: always
# build: ./docsbox-master/docsbox
# links:
# - redis:redis
# volumes:
# - web
# command: rqscheduler -H redis -p 6379 -d 0
# networks: ['stack']
#
# nginx:
# restart: always
# build: ./docsbox-master/nginx/
# ports:
# - "81:80"
# volumes:
# - web
# links:
# - web:web
# networks: ['stack']
#
# redis:
# restart: always
# image: redis:latest
# expose:
# - "6379"
# volumes:
# - redisdata:/data
# networks: ['stack']
##########################SETTIGNS######################################################################
volumes:
#esdata:
#driver: local
redisdata:
driver: local
docsbox:
driver: local
media:
driver: local
networks: {stack: {}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -euo pipefail
beat=$1
until curl -s http://kibana:5601; do
sleep 2
done
sleep 5
# Load the sample dashboards for the Beat.
# REF: https://www.elastic.co/guide/en/beats/metricbeat/master/metricbeat-sample-dashboards.html
${beat} setup \
-E setup.kibana.host=kibana \
-E setup.kibana.username=elastic \
-E setup.kibana.password=${ELASTIC_PASSWORD} \
-E output.elasticsearch.password=${ELASTIC_PASSWORD}

View File

@ -0,0 +1,10 @@
#!/bin/bash
set -euo pipefail
es_url=http://elastic:${ELASTIC_PASSWORD}@elasticsearch:9200
# Wait for Elasticsearch to start up before doing anything.
until curl -s $es_url -o /dev/null; do
sleep 1
done

View File

@ -0,0 +1,10 @@
#!/bin/bash
set -euo pipefail
es_url=http://elastic:${ELASTIC_PASSWORD}@elasticsearch:9200
# Wait for Elasticsearch to start up before doing anything.
until curl -s $es_url -o /dev/null; do
sleep 1
done

2
ELK.Docker/old/stack/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!/.gitignore

View File

@ -0,0 +1,20 @@
---
## Default Elasticsearch configuration from elasticsearch-docker.
## from https://github.com/elastic/elasticsearch-docker/blob/master/build/elasticsearch/elasticsearch.yml
#
network.host: 0.0.0.0
# minimum_master_nodes need to be explicitly set when bound on a public IP
# set to 1 to allow single node clusters
# Details: https://github.com/elastic/elasticsearch/pull/17288
# discovery.zen.minimum_master_nodes: 1
## Use single node discovery in order to disable production mode and avoid bootstrap checks
## see https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
#
discovery.type: single-node
## Search Guard
#
cluster.routing.allocation.disk.watermark.flood_stage: 99%

View File

@ -0,0 +1,179 @@
#https://github.com/elastic/elasticsearch/blob/7.4/distribution/src/config/log4j2.properties
status = error
# log action execution errors for easier debugging
logger.action.name = org.elasticsearch.action
logger.action.level = debug
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
######## Server JSON ############################
appender.rolling.type = RollingFile
appender.rolling.name = rolling
appender.rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_server.json
appender.rolling.layout.type = ESJsonLayout
appender.rolling.layout.type_name = server
appender.rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-%i.json.gz
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size = 128MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.fileIndex = nomax
appender.rolling.strategy.action.type = Delete
appender.rolling.strategy.action.basepath = ${sys:es.logs.base_path}
appender.rolling.strategy.action.condition.type = IfFileName
appender.rolling.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-*
appender.rolling.strategy.action.condition.nested_condition.type = IfAccumulatedFileSize
appender.rolling.strategy.action.condition.nested_condition.exceeds = 2GB
################################################
######## Server - old style pattern ###########
appender.rolling_old.type = RollingFile
appender.rolling_old.name = rolling_old
appender.rolling_old.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}.log
appender.rolling_old.layout.type = PatternLayout
appender.rolling_old.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
appender.rolling_old.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}-%d{yyyy-MM-dd}-%i.log.gz
appender.rolling_old.policies.type = Policies
appender.rolling_old.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling_old.policies.time.interval = 1
appender.rolling_old.policies.time.modulate = true
appender.rolling_old.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling_old.policies.size.size = 128MB
appender.rolling_old.strategy.type = DefaultRolloverStrategy
appender.rolling_old.strategy.fileIndex = nomax
appender.rolling_old.strategy.action.type = Delete
appender.rolling_old.strategy.action.basepath = ${sys:es.logs.base_path}
appender.rolling_old.strategy.action.condition.type = IfFileName
appender.rolling_old.strategy.action.condition.glob = ${sys:es.logs.cluster_name}-*
appender.rolling_old.strategy.action.condition.nested_condition.type = IfAccumulatedFileSize
appender.rolling_old.strategy.action.condition.nested_condition.exceeds = 2GB
################################################
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
rootLogger.appenderRef.rolling.ref = rolling
rootLogger.appenderRef.rolling_old.ref = rolling_old
######## Deprecation JSON #######################
appender.deprecation_rolling.type = RollingFile
appender.deprecation_rolling.name = deprecation_rolling
appender.deprecation_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_deprecation.json
appender.deprecation_rolling.layout.type = ESJsonLayout
appender.deprecation_rolling.layout.type_name = deprecation
appender.deprecation_rolling.layout.esmessagefields=x-opaque-id
appender.deprecation_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_deprecation-%i.json.gz
appender.deprecation_rolling.policies.type = Policies
appender.deprecation_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.deprecation_rolling.policies.size.size = 1GB
appender.deprecation_rolling.strategy.type = DefaultRolloverStrategy
appender.deprecation_rolling.strategy.max = 4
#################################################
######## Deprecation - old style pattern #######
appender.deprecation_rolling_old.type = RollingFile
appender.deprecation_rolling_old.name = deprecation_rolling_old
appender.deprecation_rolling_old.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_deprecation.log
appender.deprecation_rolling_old.layout.type = PatternLayout
appender.deprecation_rolling_old.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
appender.deprecation_rolling_old.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_deprecation-%i.log.gz
appender.deprecation_rolling_old.policies.type = Policies
appender.deprecation_rolling_old.policies.size.type = SizeBasedTriggeringPolicy
appender.deprecation_rolling_old.policies.size.size = 1GB
appender.deprecation_rolling_old.strategy.type = DefaultRolloverStrategy
appender.deprecation_rolling_old.strategy.max = 4
#################################################
logger.deprecation.name = org.elasticsearch.deprecation
logger.deprecation.level = warn
logger.deprecation.appenderRef.deprecation_rolling.ref = deprecation_rolling
logger.deprecation.appenderRef.deprecation_rolling_old.ref = deprecation_rolling_old
logger.deprecation.additivity = false
######## Search slowlog JSON ####################
appender.index_search_slowlog_rolling.type = RollingFile
appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling
appender.index_search_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs\
.cluster_name}_index_search_slowlog.json
appender.index_search_slowlog_rolling.layout.type = ESJsonLayout
appender.index_search_slowlog_rolling.layout.type_name = index_search_slowlog
appender.index_search_slowlog_rolling.layout.esmessagefields=message,took,took_millis,total_hits,types,stats,search_type,total_shards,source,id
appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs\
.cluster_name}_index_search_slowlog-%i.json.gz
appender.index_search_slowlog_rolling.policies.type = Policies
appender.index_search_slowlog_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.index_search_slowlog_rolling.policies.size.size = 1GB
appender.index_search_slowlog_rolling.strategy.type = DefaultRolloverStrategy
appender.index_search_slowlog_rolling.strategy.max = 4
#################################################
######## Search slowlog - old style pattern ####
appender.index_search_slowlog_rolling_old.type = RollingFile
appender.index_search_slowlog_rolling_old.name = index_search_slowlog_rolling_old
appender.index_search_slowlog_rolling_old.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_search_slowlog.log
appender.index_search_slowlog_rolling_old.layout.type = PatternLayout
appender.index_search_slowlog_rolling_old.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
appender.index_search_slowlog_rolling_old.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_search_slowlog-%i.log.gz
appender.index_search_slowlog_rolling_old.policies.type = Policies
appender.index_search_slowlog_rolling_old.policies.size.type = SizeBasedTriggeringPolicy
appender.index_search_slowlog_rolling_old.policies.size.size = 1GB
appender.index_search_slowlog_rolling_old.strategy.type = DefaultRolloverStrategy
appender.index_search_slowlog_rolling_old.strategy.max = 4
#################################################
logger.index_search_slowlog_rolling.name = index.search.slowlog
logger.index_search_slowlog_rolling.level = trace
logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling.ref = index_search_slowlog_rolling
logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling_old.ref = index_search_slowlog_rolling_old
logger.index_search_slowlog_rolling.additivity = false
######## Indexing slowlog JSON ##################
appender.index_indexing_slowlog_rolling.type = RollingFile
appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling
appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_indexing_slowlog.json
appender.index_indexing_slowlog_rolling.layout.type = ESJsonLayout
appender.index_indexing_slowlog_rolling.layout.type_name = index_indexing_slowlog
appender.index_indexing_slowlog_rolling.layout.esmessagefields=message,took,took_millis,doc_type,id,routing,source
appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_indexing_slowlog-%i.json.gz
appender.index_indexing_slowlog_rolling.policies.type = Policies
appender.index_indexing_slowlog_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.index_indexing_slowlog_rolling.policies.size.size = 1GB
appender.index_indexing_slowlog_rolling.strategy.type = DefaultRolloverStrategy
appender.index_indexing_slowlog_rolling.strategy.max = 4
#################################################
######## Indexing slowlog - old style pattern ##
appender.index_indexing_slowlog_rolling_old.type = RollingFile
appender.index_indexing_slowlog_rolling_old.name = index_indexing_slowlog_rolling_old
appender.index_indexing_slowlog_rolling_old.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_indexing_slowlog.log
appender.index_indexing_slowlog_rolling_old.layout.type = PatternLayout
appender.index_indexing_slowlog_rolling_old.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] [%node_name]%marker %m%n
appender.index_indexing_slowlog_rolling_old.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}\
_index_indexing_slowlog-%i.log.gz
appender.index_indexing_slowlog_rolling_old.policies.type = Policies
appender.index_indexing_slowlog_rolling_old.policies.size.type = SizeBasedTriggeringPolicy
appender.index_indexing_slowlog_rolling_old.policies.size.size = 1GB
appender.index_indexing_slowlog_rolling_old.strategy.type = DefaultRolloverStrategy
appender.index_indexing_slowlog_rolling_old.strategy.max = 4
#################################################
logger.index_indexing_slowlog.name = index.indexing.slowlog.index
logger.index_indexing_slowlog.level = trace
logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling
logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling_old.ref = index_indexing_slowlog_rolling_old
logger.index_indexing_slowlog.additivity = false

View File

@ -0,0 +1,16 @@
#filebeat.registry_file: /usr/share/filebeat/registry
filebeat.inputs:
- type: log
paths:
- /usr/share/filebeat/log_data/dmp/openDMP*.log
tags: ["audit"]
enabled: true
reload.enabled: true
reload.period: 10s
multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
output.logstash:
hosts: ["logstash:31312"]
bulk_max_size: 128

View File

@ -0,0 +1,17 @@
---
## Default Kibana configuration from kibana-docker.
## from https://github.com/elastic/kibana-docker/blob/master/build/kibana/config/kibana.yml
#
server.name: kibana
server.host: "0"
## Custom configuration
#
#server.basePath: "/eformslogs"
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
#elasticsearch.ssl.certificateAuthorities: [ "/usr/share/kibana/certificate_authorities/ca.crt" ]
elasticsearch.username: "kibana"
elasticsearch.password: ""
server.ssl.enabled: false
#server.ssl.key: "/usr/share/kibana/certificates/kibana.key"
#server.ssl.certificate: "/usr/share/kibana/certificates/kibana.crt"

View File

@ -0,0 +1,103 @@
#https://github.com/elastic/logstash/blob/7.4/config/log4j2.properties
status = error
name = LogstashPropertiesConfig
appender.console.type = Console
appender.console.name = plain_console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n
appender.json_console.type = Console
appender.json_console.name = json_console
appender.json_console.layout.type = JSONLayout
appender.json_console.layout.compact = true
appender.json_console.layout.eventEol = true
appender.rolling.type = RollingFile
appender.rolling.name = plain_rolling
appender.rolling.fileName = ${sys:ls.logs}/logstash-${sys:ls.log.format}.log
appender.rolling.filePattern = ${sys:ls.logs}/logstash-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 1
appender.rolling.policies.time.modulate = true
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c]%notEmpty{[%X{pipeline.id}]} %m%n
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size = 100MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 30
appender.json_rolling.type = RollingFile
appender.json_rolling.name = json_rolling
appender.json_rolling.fileName = ${sys:ls.logs}/logstash-${sys:ls.log.format}.log
appender.json_rolling.filePattern = ${sys:ls.logs}/logstash-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz
appender.json_rolling.policies.type = Policies
appender.json_rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.json_rolling.policies.time.interval = 1
appender.json_rolling.policies.time.modulate = true
appender.json_rolling.layout.type = JSONLayout
appender.json_rolling.layout.compact = true
appender.json_rolling.layout.eventEol = true
appender.json_rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.json_rolling.policies.size.size = 100MB
appender.json_rolling.strategy.type = DefaultRolloverStrategy
appender.json_rolling.strategy.max = 30
rootLogger.level = ${sys:ls.log.level}
rootLogger.appenderRef.console.ref = ${sys:ls.log.format}_console
rootLogger.appenderRef.rolling.ref = ${sys:ls.log.format}_rolling
# Slowlog
appender.console_slowlog.type = Console
appender.console_slowlog.name = plain_console_slowlog
appender.console_slowlog.layout.type = PatternLayout
appender.console_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.json_console_slowlog.type = Console
appender.json_console_slowlog.name = json_console_slowlog
appender.json_console_slowlog.layout.type = JSONLayout
appender.json_console_slowlog.layout.compact = true
appender.json_console_slowlog.layout.eventEol = true
appender.rolling_slowlog.type = RollingFile
appender.rolling_slowlog.name = plain_rolling_slowlog
appender.rolling_slowlog.fileName = ${sys:ls.logs}/logstash-slowlog-${sys:ls.log.format}.log
appender.rolling_slowlog.filePattern = ${sys:ls.logs}/logstash-slowlog-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz
appender.rolling_slowlog.policies.type = Policies
appender.rolling_slowlog.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling_slowlog.policies.time.interval = 1
appender.rolling_slowlog.policies.time.modulate = true
appender.rolling_slowlog.layout.type = PatternLayout
appender.rolling_slowlog.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %m%n
appender.rolling_slowlog.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling_slowlog.policies.size.size = 100MB
appender.rolling_slowlog.strategy.type = DefaultRolloverStrategy
appender.rolling_slowlog.strategy.max = 30
appender.json_rolling_slowlog.type = RollingFile
appender.json_rolling_slowlog.name = json_rolling_slowlog
appender.json_rolling_slowlog.fileName = ${sys:ls.logs}/logstash-slowlog-${sys:ls.log.format}.log
appender.json_rolling_slowlog.filePattern = ${sys:ls.logs}/logstash-slowlog-${sys:ls.log.format}-%d{yyyy-MM-dd}-%i.log.gz
appender.json_rolling_slowlog.policies.type = Policies
appender.json_rolling_slowlog.policies.time.type = TimeBasedTriggeringPolicy
appender.json_rolling_slowlog.policies.time.interval = 1
appender.json_rolling_slowlog.policies.time.modulate = true
appender.json_rolling_slowlog.layout.type = JSONLayout
appender.json_rolling_slowlog.layout.compact = true
appender.json_rolling_slowlog.layout.eventEol = true
appender.json_rolling_slowlog.policies.size.type = SizeBasedTriggeringPolicy
appender.json_rolling_slowlog.policies.size.size = 100MB
appender.json_rolling_slowlog.strategy.type = DefaultRolloverStrategy
appender.json_rolling_slowlog.strategy.max = 30
logger.slowlog.name = slowlog
logger.slowlog.level = trace
logger.slowlog.appenderRef.console_slowlog.ref = ${sys:ls.log.format}_console_slowlog
logger.slowlog.appenderRef.rolling_slowlog.ref = ${sys:ls.log.format}_rolling_slowlog
logger.slowlog.additivity = false
logger.licensereader.name = logstash.licensechecker.licensereader
logger.licensereader.level = error

View File

@ -0,0 +1,10 @@
---
## Default Logstash configuration from logstash-docker.
## from https://github.com/elastic/logstash-docker/blob/master/build/logstash/config/logstash-oss.yml
#
http.host: "0.0.0.0"
config.reload.automatic: true
config.reload.interval: 300s
path.queue: /usr/share/logstash/queue
path.dead_letter_queue: /usr/share/logstash/dead_letter_queue
xpack.monitoring.elasticsearch.password:

View File

@ -0,0 +1,18 @@
- pipeline.id: open_dmp_beats
queue.type: persisted
queue.max_bytes: 50mb
dead_letter_queue.enable: true
path.config: "/usr/share/logstash/pipeline/open_dmp_beats.conf"
queue.checkpoint.writes: 32
- pipeline.id: open_dmp_main
queue.type: persisted
queue.max_bytes: 50mb
dead_letter_queue.enable: true
path.config: "/usr/share/logstash/pipeline/open_dmp_main.conf"
queue.checkpoint.writes: 32
- pipeline.id: open_dmp_send_to_elastic
queue.type: persisted
queue.max_bytes: 50mb
dead_letter_queue.enable: true
path.config: "/usr/share/logstash/pipeline/open_dmp_send_to_elastic.conf"
queue.checkpoint.writes: 32

View File

@ -0,0 +1,14 @@
input {
beats {
port => 31312
ssl => false
client_inactivity_timeout => 3000
}
}
filter {
}
output {
pipeline { send_to => open_dmp_main }
}

View File

@ -0,0 +1,19 @@
input {
pipeline { address => open_dmp_main }
}
filter {
grok {
match => { "message" => "(?<timestamp>%{DATE} %{TIME})%{SPACE}%{LOGLEVEL:level} %{NUMBER:pid} --- \[%{DATA:thread}\] %{DATA:class}%{SPACE}: %{GREEDYDATA:logmessage}" }
}
if "_grokparsefailure" not in [tags] {
mutate
{
remove_field => [ "message" ]
}
}
}
output {
pipeline { send_to => open_dmp_send_to_elastic }
}

View File

@ -0,0 +1,19 @@
input {
pipeline { address => open_dmp_send_to_elastic }
}
filter {
}
output {
elasticsearch {
hosts => "elasticsearch:9200"
user => elastic
password =>
index =>"opendmp.logs"
#manage_template => true
#template => "/usr/share/logstash/templates/audit/openDMP.json"
#template_name => "cite.elas.openDMP-audit*"
#template_overwrite => true
}
}

66
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,66 @@
def pipelineContext = [:]
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build API') {
steps {
script {
pipelineContext.apiImage = docker.build("open-dmp-api:${env.BUILD_ID}", "-f dmp-backend/Dockerfile.CI dmp-backend/")
}
}
}
stage('Build WebApp') {
steps {
script {
pipelineContext.webappImage = docker.build("open-dmp-webapp:${env.BUILD_ID}", "-f dmp-frontend/Dockerfile.CI dmp-frontend/")
}
}
}
//stage('SonarQube analysis') {
// steps {
// script {
// def scannerHome = tool 'SonarQube Scanner 4.3';
// withSonarQubeEnv('SonarQube') { // If you have configured more than one global server connection, you can specify its name
// sh "${scannerHome}/bin/sonar-scanner"
// }
// }
// }
//}
//// waiting for sonar results based into the configured web hook in Sonar server which push the status back to jenkins
//stage('SonarQube scan result check') {
// steps {
// timeout(time: 2, unit: 'MINUTES') {
// retry(3) {
// script {
// def qg = waitForQualityGate()
// if (qg.status != 'OK') {
// error "Pipeline aborted due to quality gate failure: ${qg.status}"
// }
// }
// }
// }
// }
//}
stage('Pushing to Docker Registry') {
steps {
script {
docker.withRegistry('http://drepo.local.cite.gr', 'b2c651c1-9a3b-4a98-a6da-e1dd7a20f512') {
pipelineContext.apiImage.push()
pipelineContext.webappImage.push()
}
}
}
}
}
}

View File

@ -1,3 +1,9 @@
**Important note: The deployment, troubleshooting, maintenance and operation of on-premises / self-served OpenDMP instances for development, testing or production use, shall be the sole responsibility of the adopter. No support is guaranteed by OpenDMP implentation team for issues that may be encountered during deployment, extension or operation of such installations.**
**Documentation is provided on a best-effort basis for the code and processes around the development, deployment and operation of OpenDMP. If you find any misalignment of the actual processes with the related documentation, please let us know so that the misalignment is addressed for the benefit of future adopters.**
# Using Docker Compose with Argos
ARGOS is an open extensible service that simplifies the management, validation, monitoring and maintenance and of Data Management Plans. It allows actors (researchers, managers, supervisors etc) to create actionable DMPs that may be freely exchanged among infrastructures for carrying out specific aspects of the Data management process in accordance with the intentions and commitment of Data owners.

View File

@ -1,38 +0,0 @@
####################################### Build stage #######################################
FROM maven:3.9-eclipse-temurin-21-alpine AS build-stage
ARG MAVEN_ACCOUNT_USR
ARG MAVEN_ACCOUNT_PSW
ARG REVISION
ARG PROFILE
ENV server_username=$MAVEN_ACCOUNT_USR
ENV server_password=$MAVEN_ACCOUNT_PSW
ARG CITE_MAVEN_REPO_URL
COPY pom.xml /build/
COPY annotation /build/annotation/
COPY annotation-web /build/annotation-web/
COPY settings.xml /root/.m2/settings.xml
RUN rm -f /build/annotation-web/src/main/resources/config/app.env
RUN rm -f /build/annotation-web/src/main/resources/config/*-devel.yml
RUN rm -f /build/annotation-web/src/main/resources/logging/*.xml
RUN rm -f /build/annotation-web/src/main/resources/certificates/*.crt
WORKDIR /build/
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} clean
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} install
# Build project
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} package
######################################## Run Stage ########################################
FROM eclipse-temurin:21-jre-ubi9-minimal
ARG PROFILE
ARG REVISION
ENV SERVER_PORT=8080
EXPOSE ${SERVER_PORT}
COPY --from=build-stage /build/annotation-web/target/annotation-web-${REVISION}.jar /app/annotation-web.jar
ENTRYPOINT ["java","-Dspring.config.additional-location=file:/config/","-Dspring.profiles.active=${PROFILE}","-Djava.security.egd=file:/dev/./urandom","-jar","/app/annotation-web.jar"]

View File

@ -1,30 +0,0 @@
####################################### Build stage #######################################
FROM maven:3.9-eclipse-temurin-21-alpine
ARG MAVEN_ACCOUNT_USR
ARG MAVEN_ACCOUNT_PSW
ARG REVISION
ARG PROFILE
ARG ORACLE_URL
ARG ORACLE_TOKEN
ENV server_username=$MAVEN_ACCOUNT_USR
ENV server_password=$MAVEN_ACCOUNT_PSW
ARG CITE_MAVEN_REPO_URL
COPY pom.xml /build/
COPY annotation /build/annotation/
COPY annotation-web /build/annotation-web/
COPY settings.xml /root/.m2/settings.xml
RUN rm -f /build/annotation-web/src/main/resources/config/app.env
RUN rm -f /build/annotation-web/src/main/resources/config/*-devel.yml
RUN rm -f /build/annotation-web/src/main/resources/logging/*.xml
RUN rm -f /build/annotation-web/src/main/resources/certificates/*.crt
COPY oracle.local.cite.gr.crt $JAVA_HOME/conf/security
RUN cd "$JAVA_HOME"/conf/security && keytool -cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias oraclecert -file oracle.local.cite.gr.crt
WORKDIR /build/
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} clean
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} install
RUN mvn -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} package
RUN mvn sonar:sonar -Drevision=${REVISION} -DciteMavenRepoUrl=${CITE_MAVEN_REPO_URL} -P${PROFILE} -Dsonar.projectKey=OpenDMP:annotation-api -Dsonar.login=${ORACLE_TOKEN} -Dsonar.host.url=${ORACLE_URL} -Dsonar.projectName='OpenDMP Annotation API'

View File

@ -1,33 +0,0 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>gr.cite</groupId>
<artifactId>annotation-service-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>annotation-web</artifactId>
<version>${revision}</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.release>21</maven.compiler.release>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<revision>1.0.0-SNAPSHOT</revision>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>gr.cite</groupId>
<artifactId>annotation</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>gr.cite</groupId>
<artifactId>oidc-authz</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>gr.cite</groupId>
<artifactId>cache</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>gr.cite</groupId>
<artifactId>exceptions-web</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>gr.cite</groupId>
<artifactId>cors-web</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,26 +0,0 @@
package gr.cite.annotation.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(
scanBasePackages = {
"gr.cite.annotation.*",
"gr.cite",
"gr.cite.queueoutbox",
"gr.cite.queueinbox",
"gr.cite.annotation.integrationevent",
"gr.cite.tools",
"gr.cite.commons"})
@EntityScan({
"gr.cite.annotation.data"})
@EnableAsync
public class AnnotationApplication {
public static void main(String[] args) {
SpringApplication.run(AnnotationApplication.class, args);
}
}

View File

@ -1,40 +0,0 @@
package gr.cite.annotation.web;
import gr.cite.annotation.web.scope.tenant.TenantInterceptor;
import gr.cite.annotation.web.scope.tenant.TenantScopeClaimInterceptor;
import gr.cite.annotation.web.scope.tenant.TenantScopeHeaderInterceptor;
import gr.cite.annotation.web.scope.user.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
private final TenantInterceptor tenantInterceptor;
private final TenantScopeHeaderInterceptor scopeHeaderInterceptor;
private final TenantScopeClaimInterceptor scopeClaimInterceptor;
private final UserInterceptor userInterceptor;
@Autowired
public WebConfiguration(
TenantInterceptor tenantInterceptor,
TenantScopeHeaderInterceptor scopeHeaderInterceptor,
TenantScopeClaimInterceptor scopeClaimInterceptor,
UserInterceptor userInterceptor
) {
this.tenantInterceptor = tenantInterceptor;
this.scopeHeaderInterceptor = scopeHeaderInterceptor;
this.scopeClaimInterceptor = scopeClaimInterceptor;
this.userInterceptor = userInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
int order = 1;
registry.addWebRequestInterceptor(scopeHeaderInterceptor).order(order++);
registry.addWebRequestInterceptor(scopeClaimInterceptor).order(order++);
registry.addWebRequestInterceptor(userInterceptor).order(order++);
registry.addWebRequestInterceptor(tenantInterceptor).order(order++);
}
}

View File

@ -1,56 +0,0 @@
package gr.cite.annotation.web.authorization;
import gr.cite.annotation.authorization.AffiliatedAuthorizationRequirement;
import gr.cite.annotation.authorization.AffiliatedResource;
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("affiliatedAuthorizationHandler")
public class AffiliatedAuthorizationHandler extends AuthorizationHandler<AffiliatedAuthorizationRequirement> {
private final CustomPermissionAttributesConfiguration myConfiguration;
@Autowired
public AffiliatedAuthorizationHandler(CustomPermissionAttributesConfiguration myConfiguration) {
this.myConfiguration = myConfiguration;
}
@Override
public int handleRequirement(AuthorizationHandlerContext context, Object resource, AuthorizationRequirement requirement) {
AffiliatedAuthorizationRequirement req = (AffiliatedAuthorizationRequirement) requirement;
if (req.getRequiredPermissions() == null)
return ACCESS_NOT_DETERMINED;
AffiliatedResource rs = (AffiliatedResource) resource;
boolean isAuthenticated = ((MyPrincipal) context.getPrincipal()).isAuthenticated();
if (!isAuthenticated)
return ACCESS_NOT_DETERMINED;
if (myConfiguration.getMyPolicies() == null)
return ACCESS_NOT_DETERMINED;
int hits = 0;
Boolean entityAffiliated = rs != null && rs.getAffiliated() != null ? rs.getAffiliated() : null;
for (String permission : req.getRequiredPermissions()) {
CustomPermissionAttributesProperties.MyPermission policy = myConfiguration.getMyPolicies().get(permission);
boolean hasPermission = policy != null && policy.getEntityAffiliated() != null && policy.getEntityAffiliated() && entityAffiliated != null && entityAffiliated;
if (hasPermission) hits += 1;
}
if ((req.getMatchAll() && req.getRequiredPermissions().size() == hits) || (!req.getMatchAll() && hits > 0))
return ACCESS_GRANTED;
return ACCESS_NOT_DETERMINED;
}
@Override
public Class<? extends AuthorizationRequirement> supporting() {
return AffiliatedAuthorizationRequirement.class;
}
}

View File

@ -1,24 +0,0 @@
package gr.cite.annotation.web.authorization;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@Configuration
@EnableConfigurationProperties(CustomPermissionAttributesProperties.class)
public class CustomPermissionAttributesConfiguration {
private final CustomPermissionAttributesProperties properties;
@Autowired
public CustomPermissionAttributesConfiguration(CustomPermissionAttributesProperties properties) {
this.properties = properties;
}
public HashMap<String, CustomPermissionAttributesProperties.MyPermission> getMyPolicies() {
return properties.getPolicies();
}
}

View File

@ -1,38 +0,0 @@
package gr.cite.annotation.web.authorization;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.ConstructorBinding;
import java.util.HashMap;
@ConfigurationProperties(prefix = "permissions")
@ConditionalOnProperty(prefix = "permissions", name = "enabled", havingValue = "true")
public class CustomPermissionAttributesProperties {
private final HashMap<String, MyPermission> policies;
@ConstructorBinding
public CustomPermissionAttributesProperties(HashMap<String, MyPermission> policies) {
this.policies = policies;
}
public HashMap<String, MyPermission> getPolicies() {
return policies;
}
public static class MyPermission {
private final Boolean entityAffiliated;
@ConstructorBinding
public MyPermission(Boolean entityAffiliated) {
this.entityAffiliated = entityAffiliated;
}
public Boolean getEntityAffiliated() {
return entityAffiliated;
}
}
}

View File

@ -1,44 +0,0 @@
package gr.cite.annotation.web.authorization;
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.AuthorizationHandlerContext;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.annotation.authorization.OwnedAuthorizationRequirement;
import gr.cite.annotation.authorization.OwnedResource;
import gr.cite.annotation.common.scope.user.UserScope;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("ownedAuthorizationHandler")
public class OwnedAuthorizationHandler extends AuthorizationHandler<OwnedAuthorizationRequirement> {
private final UserScope userScope;
@Autowired
public OwnedAuthorizationHandler(UserScope userScope) {
this.userScope = userScope;
}
@Override
public int handleRequirement(AuthorizationHandlerContext context, Object resource, AuthorizationRequirement requirement) {
OwnedAuthorizationRequirement req = (OwnedAuthorizationRequirement) requirement;
OwnedResource rs = (OwnedResource) resource;
boolean isAuthenticated = ((MyPrincipal) context.getPrincipal()).isAuthenticated();
if (!isAuthenticated) return ACCESS_NOT_DETERMINED;
if (this.userScope.getUserIdSafe() == null) return ACCESS_NOT_DETERMINED;
if (rs != null && rs.getUserIds() != null && rs.getUserIds().contains(this.userScope.getUserIdSafe())) return ACCESS_GRANTED;
return ACCESS_NOT_DETERMINED;
}
@Override
public Class<? extends AuthorizationRequirement> supporting() {
return OwnedAuthorizationRequirement.class;
}
}

View File

@ -1,25 +0,0 @@
package gr.cite.annotation.web.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class AppMessageSourceConfiguration {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages/messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
@Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
}

View File

@ -1,152 +0,0 @@
package gr.cite.annotation.web.config;
import gr.cite.annotation.authorization.AffiliatedAuthorizationRequirement;
import gr.cite.annotation.authorization.AffiliatedResource;
import gr.cite.annotation.web.authorization.AffiliatedAuthorizationHandler;
import gr.cite.commons.web.authz.handler.AuthorizationHandler;
import gr.cite.commons.web.authz.handler.PermissionClientAuthorizationHandler;
import gr.cite.commons.web.authz.policy.AuthorizationRequirement;
import gr.cite.commons.web.authz.policy.AuthorizationRequirementMapper;
import gr.cite.commons.web.authz.policy.AuthorizationResource;
import gr.cite.commons.web.authz.policy.resolver.AuthorizationPolicyConfigurer;
import gr.cite.commons.web.authz.policy.resolver.AuthorizationPolicyResolverStrategy;
import gr.cite.commons.web.oidc.configuration.WebSecurityProperties;
import gr.cite.annotation.authorization.OwnedAuthorizationRequirement;
import gr.cite.annotation.authorization.OwnedResource;
import gr.cite.annotation.web.authorization.OwnedAuthorizationHandler;
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManagerResolver;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
private final WebSecurityProperties webSecurityProperties;
private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
private final Filter apiKeyFilter;
private final OwnedAuthorizationHandler ownedAuthorizationHandler;
private final AffiliatedAuthorizationHandler affiliatedAuthorizationHandler;
@Autowired
public SecurityConfiguration(WebSecurityProperties webSecurityProperties,
@Qualifier("tokenAuthenticationResolver") AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver,
@Qualifier("apiKeyFilter") Filter apiKeyFilter,
@Qualifier("ownedAuthorizationHandler") OwnedAuthorizationHandler ownedAuthorizationHandler,
@Qualifier("affiliatedAuthorizationHandler") AffiliatedAuthorizationHandler affiliatedAuthorizationHandler) {
this.webSecurityProperties = webSecurityProperties;
this.authenticationManagerResolver = authenticationManagerResolver;
this.apiKeyFilter = apiKeyFilter;
this.ownedAuthorizationHandler = ownedAuthorizationHandler;
this.affiliatedAuthorizationHandler = affiliatedAuthorizationHandler;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
HttpSecurity tempHttp = http
.csrf(AbstractHttpConfigurer::disable)
.cors(httpSecurityCorsConfigurer -> {})
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.addFilterBefore(apiKeyFilter, AbstractPreAuthenticatedProcessingFilter.class)
.authorizeHttpRequests(authRequest ->
authRequest.requestMatchers(buildAntPatterns(webSecurityProperties.getAllowedEndpoints())).anonymous()
.requestMatchers(buildAntPatterns(webSecurityProperties.getAuthorizedEndpoints())).authenticated())
.sessionManagement( sessionManagementConfigurer-> sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.NEVER))
.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
return tempHttp.build();
}
@Bean
AuthorizationPolicyConfigurer authorizationPolicyConfigurer() {
return new AuthorizationPolicyConfigurer() {
@Override
public AuthorizationPolicyResolverStrategy strategy() {
return AuthorizationPolicyResolverStrategy.STRICT_CONSENSUS_BASED;
}
//Here you can register your custom authorization handlers, which will get used as well as the existing ones
//This is optional and can be omitted
//If not set / set to null, only the default authorization handlers will be used
@Override
public List<AuthorizationHandler<? extends AuthorizationRequirement>> addCustomHandlers() {
return List.of(affiliatedAuthorizationHandler, ownedAuthorizationHandler);
}
//Here you can register your custom authorization requirements (if any)
//This is optional and can be omitted
//If not set / set to null, only the default authorization requirements will be used
@Override
public List<? extends AuthorizationRequirement> extendRequirements() {
return List.of(
// new TimeOfDayAuthorizationRequirement(new TimeOfDay("08:00","16:00"), true)
);
}
//Here you can select handlers you want to disable by providing the classes they are implemented by
//You can disable any handler (including any custom one)
//This is optional and can be omitted
//If not set / set to null, all the handlers will be invoked, based on their requirement support
//In the example below, the default client handler will be ignored by the resolver
@Override
public List<Class<? extends AuthorizationHandler<? extends AuthorizationRequirement>>> disableHandlers() {
return new ArrayList<>();
}
};
}
@Bean
AuthorizationRequirementMapper authorizationRequirementMapper() {
return new AuthorizationRequirementMapper() {
@Override
public AuthorizationRequirement map(AuthorizationResource resource, boolean matchAll, String[] permissions) {
Class<?> type = resource.getClass();
if (!AuthorizationResource.class.isAssignableFrom(type)) throw new IllegalArgumentException("resource");
if (OwnedResource.class.equals(type)) {
return new OwnedAuthorizationRequirement();
}
if (AffiliatedResource.class.equals(type)) {
return new AffiliatedAuthorizationRequirement(matchAll, permissions);
}
throw new IllegalArgumentException("resource");
}
};
}
private String[] buildAntPatterns(Set<String> endpoints) {
if (endpoints == null) {
return new String[0];
}
return endpoints.stream()
.filter(endpoint -> endpoint != null && !endpoint.isBlank())
.map(endpoint -> "/" + stripUnnecessaryCharacters(endpoint) + "/**")
.toArray(String[]::new);
}
private String stripUnnecessaryCharacters(String endpoint) {
endpoint = endpoint.strip();
if (endpoint.startsWith("/")) {
endpoint = endpoint.substring(1);
}
if (endpoint.endsWith("/")) {
endpoint = endpoint.substring(0, endpoint.length() - 1);
}
return endpoint;
}
}

View File

@ -1,193 +0,0 @@
package gr.cite.annotation.web.controllerhandler;
import gr.cite.annotation.common.JsonHandlingService;
import gr.cite.tools.exception.*;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import java.text.MessageFormat;
import java.util.Map;
@RestControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(GlobalExceptionHandler.class));
private final JsonHandlingService jsonHandlingService;
public GlobalExceptionHandler(JsonHandlingService jsonHandlingService) {
this.jsonHandlingService = jsonHandlingService;
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleUnexpectedErrors(Exception exception, WebRequest request) throws Exception {
HandledException handled = this.handleException(exception, request);
this.log(handled.getLevel(), exception, MessageFormat.format("returning code {0} and payload {1}", handled.getStatusCode(), handled.getMessage()));
return new ResponseEntity<>(handled.getMessage(), handled.getStatusCode());
}
public void log(System.Logger.Level level, Exception e, String message) {
if (level != null) {
switch (level) {
case TRACE:
logger.trace(message, e);
break;
case DEBUG:
logger.debug(message, e);
break;
case INFO:
logger.info(message, e);
break;
case WARNING:
logger.warn(message, e);
break;
case ERROR:
logger.error(message, e);
break;
}
}
}
public HandledException handleException(Exception exception, WebRequest request) throws Exception {
HttpStatus statusCode;
Map<String, Object> result;
System.Logger.Level logLevel;
switch (exception){
case MyNotFoundException myNotFoundException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.NOT_FOUND;
int code = myNotFoundException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myNotFoundException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myNotFoundException.getMessage())
);
}
}
case MyUnauthorizedException myUnauthorizedException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.UNAUTHORIZED;
int code = myUnauthorizedException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myUnauthorizedException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myUnauthorizedException.getMessage())
);
}
}
case MyForbiddenException myForbiddenException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.FORBIDDEN;
int code = myForbiddenException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myForbiddenException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myForbiddenException.getMessage())
);
}
}
case MyValidationException myValidationException -> {
logLevel = System.Logger.Level.DEBUG;
statusCode = HttpStatus.BAD_REQUEST;
int code = myValidationException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myValidationException.getMessage()),
Map.entry("message", myValidationException.getErrors())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myValidationException.getMessage()),
Map.entry("message", myValidationException.getErrors())
);
}
}
case MyApplicationException myApplicationException -> {
logLevel = System.Logger.Level.ERROR;
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
int code = myApplicationException.getCode();
if (code > 0) {
result = Map.ofEntries(
Map.entry("code", code),
Map.entry("error", myApplicationException.getMessage())
);
}
else {
result = Map.ofEntries(
Map.entry("error", myApplicationException.getMessage())
);
}
}
default -> {
logLevel = System.Logger.Level.ERROR;
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
result = Map.ofEntries(
Map.entry("error", "System error")
);
}
}
String serialization = this.jsonHandlingService.toJsonSafe(result);
return new HandledException(statusCode, serialization, logLevel);
}
public static class HandledException{
public HttpStatus statusCode;
public String message;
public System.Logger.Level level;
public HandledException(HttpStatus statusCode, String message, System.Logger.Level level) {
this.statusCode = statusCode;
this.message = message;
this.level = level;
}
public HttpStatus getStatusCode() {
return statusCode;
}
public void setStatusCode(HttpStatus statusCode) {
this.statusCode = statusCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public System.Logger.Level getLevel() {
return level;
}
public void setLevel(System.Logger.Level level) {
this.level = level;
}
}
}

View File

@ -1,132 +0,0 @@
package gr.cite.annotation.web.controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import gr.cite.annotation.audit.AuditableAction;
import gr.cite.annotation.authorization.AuthorizationFlags;
import gr.cite.annotation.data.AnnotationEntity;
import gr.cite.annotation.model.Annotation;
import gr.cite.annotation.model.builder.AnnotationBuilder;
import gr.cite.annotation.model.censorship.AnnotationCensor;
import gr.cite.annotation.model.persist.AnnotationPersist;
import gr.cite.annotation.query.AnnotationQuery;
import gr.cite.annotation.query.lookup.AnnotationLookup;
import gr.cite.annotation.service.annotation.AnnotationService;
import gr.cite.annotation.web.model.QueryResult;
import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.censor.CensorFactory;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyApplicationException;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.exception.MyNotFoundException;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService;
import gr.cite.tools.logging.MapLogEntry;
import gr.cite.tools.validation.ValidationFilterAnnotation;
import jakarta.transaction.Transactional;
import jakarta.xml.bind.JAXBException;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import javax.management.InvalidApplicationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@RestController
@RequestMapping(path = "api/annotation", produces = MediaType.APPLICATION_JSON_VALUE)
public class AnnotationController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(AnnotationController.class));
private final CensorFactory censorFactory;
private final QueryFactory queryFactory;
private final BuilderFactory builderFactory;
private final AuditService auditService;
private final MessageSource messageSource;
private final AnnotationService annotationService;
public AnnotationController(CensorFactory censorFactory, QueryFactory queryFactory, BuilderFactory builderFactory, AuditService auditService, MessageSource messageSource, AnnotationService annotationService) {
this.censorFactory = censorFactory;
this.queryFactory = queryFactory;
this.builderFactory = builderFactory;
this.auditService = auditService;
this.messageSource = messageSource;
this.annotationService = annotationService;
}
@PostMapping("query")
public QueryResult<Annotation> query(@RequestBody AnnotationLookup lookup) {
logger.debug("querying {}", Annotation.class.getSimpleName());
this.censorFactory.censor(AnnotationCensor.class).censor(lookup.getProject(), null);
AnnotationQuery query = lookup.enrich(this.queryFactory).disableTracking().authorize(AuthorizationFlags.OwnerOrPermissionAssociated);
List<AnnotationEntity> data = query.collect();
List<Annotation> models = this.builderFactory.builder(AnnotationBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionAssociated).build(lookup.getProject(), data);
long count = (lookup.getMetadata() != null && lookup.getMetadata().getCountAll()) ? query.count() : models.size();
this.auditService.track(AuditableAction.Annotation_Query, "lookup", lookup);
return new QueryResult<>(models, count);
}
@GetMapping("{id}")
public Annotation get(@PathVariable("id") UUID id, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException {
logger.debug(new MapLogEntry("retrieving" + Annotation.class.getSimpleName()).And("id", id).And("fields", fieldSet));
this.censorFactory.censor(AnnotationCensor.class).censor(fieldSet, null);
AnnotationQuery query = this.queryFactory.query(AnnotationQuery.class).disableTracking().authorize(AuthorizationFlags.OwnerOrPermissionAssociated).ids(id);
Annotation model = this.builderFactory.builder(AnnotationBuilder.class).authorize(AuthorizationFlags.OwnerOrPermissionAssociated).build(fieldSet, query.firstAs(fieldSet));
if (model == null)
throw new MyNotFoundException(messageSource.getMessage("General_ItemNotFound", new Object[]{id, Annotation.class.getSimpleName()}, LocaleContextHolder.getLocale()));
this.auditService.track(AuditableAction.Annotation_Lookup, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("id", id),
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
));
return model;
}
@PostMapping("persist")
@Transactional
@ValidationFilterAnnotation(validator = AnnotationPersist.AnnotationPersistValidator.ValidatorName, argumentName = "model")
public Annotation persist(@RequestBody AnnotationPersist model, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, InvalidApplicationException, JAXBException, ParserConfigurationException, JsonProcessingException, TransformerException {
logger.debug(new MapLogEntry("persisting" + Annotation.class.getSimpleName()).And("model", model).And("fieldSet", fieldSet));
this.censorFactory.censor(AnnotationCensor.class).censor(fieldSet, null);
Annotation persisted = this.annotationService.persist(model, fieldSet);
this.auditService.track(AuditableAction.Annotation_Persist, Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("model", model),
new AbstractMap.SimpleEntry<String, Object>("fields", fieldSet)
));
return persisted;
}
@DeleteMapping("{id}")
@Transactional
public void delete(@PathVariable("id") UUID id) throws MyForbiddenException, InvalidApplicationException {
logger.debug(new MapLogEntry("retrieving" + Annotation.class.getSimpleName()).And("id", id));
this.annotationService.deleteAndSave(id);
this.auditService.track(AuditableAction.Annotation_Delete, "id", id);
}
}

View File

@ -1,76 +0,0 @@
package gr.cite.annotation.web.controllers;
import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.annotation.audit.AuditableAction;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.web.model.Account;
import gr.cite.annotation.web.model.AccountBuilder;
import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet;
import gr.cite.tools.logging.LoggerService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping(path = "api/annotation/principal", produces = MediaType.APPLICATION_JSON_VALUE)
public class PrincipalController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(PrincipalController.class));
private final AuditService auditService;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final AccountBuilder accountBuilder;
@Autowired
public PrincipalController(
CurrentPrincipalResolver currentPrincipalResolver,
AccountBuilder accountBuilder,
AuditService auditService) {
this.currentPrincipalResolver = currentPrincipalResolver;
this.accountBuilder = accountBuilder;
this.auditService = auditService;
}
@GetMapping("me")
public Account me(FieldSet fieldSet) {
logger.debug("me");
if (fieldSet == null || fieldSet.isEmpty()) {
fieldSet = new BaseFieldSet(
Account._isAuthenticated,
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._subject),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._userId),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._name),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._scope),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._client),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._issuedAt),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._notBefore),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._authenticatedAt),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._expiresAt),
BaseFieldSet.asIndexer(Account._principal, Account.PrincipalInfo._more),
Account._permissions);
}
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
Account me = this.accountBuilder.build(fieldSet, principal);
this.auditService.track(AuditableAction.Principal_Lookup);
//auditService.trackIdentity(AuditableAction.IdentityTracking_Action);
return me;
}
}

View File

@ -1,160 +0,0 @@
package gr.cite.annotation.web.model;
import gr.cite.tools.logging.annotation.LogSensitive;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class Account {
public static class PrincipalInfo {
public static final String _userId = "userId";
public UUID userId;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public static final String _subject = "subject";
public UUID subject;
public UUID getSubject() {
return subject;
}
public void setSubject(UUID subject) {
this.subject = subject;
}
public static final String _name = "name";
@LogSensitive
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static final String _scope = "scope";
public List<String> scope;
public List<String> getScope() {
return scope;
}
public void setScope(List<String> scope) {
this.scope = scope;
}
public static final String _client = "client";
public String client;
public String getClient() {
return client;
}
public void setClient(String client) {
this.client = client;
}
public static final String _notBefore = "notBefore";
public Instant notBefore;
public Instant getNotBefore() {
return notBefore;
}
public void setNotBefore(Instant notBefore) {
this.notBefore = notBefore;
}
public static final String _issuedAt = "issuedAt";
public Instant issuedAt;
public Instant getIssuedAt() {
return issuedAt;
}
public void setIssuedAt(Instant issuedAt) {
this.issuedAt = issuedAt;
}
public static final String _authenticatedAt = "authenticatedAt";
public Instant authenticatedAt;
public Instant getAuthenticatedAt() {
return authenticatedAt;
}
public void setAuthenticatedAt(Instant authenticatedAt) {
this.authenticatedAt = authenticatedAt;
}
public static final String _expiresAt = "expiresAt";
public Instant expiresAt;
public Instant getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(Instant expiresAt) {
this.expiresAt = expiresAt;
}
public static final String _more = "more";
@LogSensitive
public Map<String, List<String>> more;
public Map<String, List<String>> getMore() {
return more;
}
public void setMore(Map<String, List<String>> more) {
this.more = more;
}
}
public static final String _isAuthenticated = "isAuthenticated";
private Boolean isAuthenticated;
public Boolean getIsAuthenticated() {
return isAuthenticated;
}
public void setIsAuthenticated(Boolean authenticated) {
isAuthenticated = authenticated;
}
public static final String _principal = "principal";
private PrincipalInfo principal;
public PrincipalInfo getPrincipal() {
return principal;
}
public void setPrincipal(PrincipalInfo principal) {
this.principal = principal;
}
public static final String _permissions = "permissions";
private List<String> permissions;
public List<String> getPermissions() {
return permissions;
}
public void setPermissions(List<String> permissions) {
this.permissions = permissions;
}
}

View File

@ -1,86 +0,0 @@
package gr.cite.annotation.web.model;
import gr.cite.commons.web.authz.configuration.AuthorizationConfiguration;
import gr.cite.commons.web.authz.configuration.Permission;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorKeys;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.tools.fieldset.BaseFieldSet;
import gr.cite.tools.fieldset.FieldSet;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AccountBuilder {
private final ClaimExtractor claimExtractor;
private final Set<String> excludeMoreClaim;
private final AuthorizationConfiguration authorizationConfiguration;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final UserScope userScope;
public AccountBuilder(ClaimExtractor claimExtractor, AuthorizationConfiguration authorizationConfiguration, CurrentPrincipalResolver currentPrincipalResolver, UserScope userScope) {
this.claimExtractor = claimExtractor;
this.authorizationConfiguration = authorizationConfiguration;
this.currentPrincipalResolver = currentPrincipalResolver;
this.userScope = userScope;
this.excludeMoreClaim = Set.of(
ClaimExtractorKeys.Subject,
ClaimExtractorKeys.Name,
ClaimExtractorKeys.Scope,
ClaimExtractorKeys.Client,
ClaimExtractorKeys.IssuedAt,
ClaimExtractorKeys.NotBefore,
ClaimExtractorKeys.AuthenticatedAt,
ClaimExtractorKeys.ExpiresAt);
}
public Account build(FieldSet fields, MyPrincipal principal) {
Account model = new Account();
if (principal == null || !principal.isAuthenticated()) {
model.setIsAuthenticated(false);
return model;
}
model.setIsAuthenticated(true);
FieldSet principalFields = fields.extractPrefixed(BaseFieldSet.asIndexerPrefix(Account._principal));
if (!principalFields.isEmpty()) model.setPrincipal(new Account.PrincipalInfo());
if (principalFields.hasField(Account.PrincipalInfo._subject)) model.getPrincipal().setSubject(this.claimExtractor.subjectUUID(principal));
if (principalFields.hasField(Account.PrincipalInfo._userId)) model.getPrincipal().setUserId(this.userScope.getUserIdSafe());
if (principalFields.hasField(Account.PrincipalInfo._name)) model.getPrincipal().setName(this.claimExtractor.name(principal));
if (principalFields.hasField(Account.PrincipalInfo._scope)) model.getPrincipal().setScope(this.claimExtractor.scope(principal));
if (principalFields.hasField(Account.PrincipalInfo._client)) model.getPrincipal().setClient(this.claimExtractor.client(principal));
if (principalFields.hasField(Account.PrincipalInfo._issuedAt)) model.getPrincipal().setIssuedAt(this.claimExtractor.issuedAt(principal));
if (principalFields.hasField(Account.PrincipalInfo._notBefore)) model.getPrincipal().setNotBefore(this.claimExtractor.notBefore(principal));
if (principalFields.hasField(Account.PrincipalInfo._authenticatedAt)) model.getPrincipal().setAuthenticatedAt(this.claimExtractor.authenticatedAt(principal));
if (principalFields.hasField(Account.PrincipalInfo._expiresAt)) model.getPrincipal().setExpiresAt(this.claimExtractor.expiresAt(principal));
if (principalFields.hasField(Account.PrincipalInfo._more)) {
model.getPrincipal().setMore(new HashMap<>());
for (String key : this.claimExtractor.knownPublicKeys()) {
if (this.excludeMoreClaim.contains(key)) continue;
List<String> values = this.claimExtractor.asStrings(principal, key);
if (values == null || values.size() == 0) continue;
if (!model.getPrincipal().getMore().containsKey(key)) model.getPrincipal().getMore().put(key, new ArrayList<>());
model.getPrincipal().getMore().get(key).addAll(values);
}
}
if (fields.hasField(Account._permissions)) {
List<String> roles = claimExtractor.roles(currentPrincipalResolver.currentPrincipal());
Set<String> permissions = authorizationConfiguration.permissionsOfRoles(roles);
for (Map.Entry<String, Permission> permissionEntry : authorizationConfiguration.getRawPolicies().entrySet()){
if (permissionEntry.getValue().getAllowAuthenticated()){
permissions.add(permissionEntry.getKey());
}
}
model.setPermissions(new ArrayList<>(permissions));
}
return model;
}
}

View File

@ -1,37 +0,0 @@
package gr.cite.annotation.web.model;
import java.util.ArrayList;
import java.util.List;
public class QueryResult<M> {
public QueryResult() { }
public QueryResult(List<M> items, long count)
{
this.items = items;
this.count = count;
}
public List<M> items;
public long count;
public List<M> getItems() {
return items;
}
public void setItems(List<M> items) {
this.items = items;
}
public long getCount() {
return count;
}
public void setCount(long count) {
this.count = count;
}
public static QueryResult<?> Empty()
{
return new QueryResult<>(new ArrayList<>(), 0L);
}
}

View File

@ -1,10 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.tenant-by-code")
public class TenantByCodeCacheOptions extends CacheOptions {
}

View File

@ -1,76 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.event.TenantTouchedEvent;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.UUID;
@Service
public class TenantByCodeCacheService extends CacheService<TenantByCodeCacheService.TenantByCodeCacheValue> {
public static class TenantByCodeCacheValue {
public TenantByCodeCacheValue() {
}
public TenantByCodeCacheValue(String tenantCode, UUID tenantId) {
this.tenantCode = tenantCode;
this.tenantId = tenantId;
}
private String tenantCode;
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
private UUID tenantId;
public UUID getTenantId() {
return tenantId;
}
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
}
private final ConventionService conventionService;
@Autowired
public TenantByCodeCacheService(TenantByCodeCacheOptions options, ConventionService conventionService) {
super(options);
this.conventionService = conventionService;
}
@EventListener
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
if (!this.conventionService.isNullOrEmpty(event.getTenantCode()))
this.evict(this.buildKey(event.getTenantCode()));
}
@Override
protected Class<TenantByCodeCacheValue> valueClass() {
return TenantByCodeCacheValue.class;
}
@Override
public String keyOf(TenantByCodeCacheValue value) {
return this.buildKey(value.getTenantCode());
}
public String buildKey(String code) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$code$", code);
return this.generateKey(keyParts);
}
}

View File

@ -1,10 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.tenant-by-id")
public class TenantByIdCacheOptions extends CacheOptions {
}

View File

@ -1,75 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.event.TenantTouchedEvent;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Locale;
import java.util.UUID;
@Service
public class TenantByIdCacheService extends CacheService<TenantByIdCacheService.TenantByIdCacheValue> {
public static class TenantByIdCacheValue {
public TenantByIdCacheValue() {
}
public TenantByIdCacheValue(String tenantCode, UUID tenantId) {
this.tenantCode = tenantCode;
this.tenantId = tenantId;
}
private String tenantCode;
public String getTenantCode() {
return tenantCode;
}
public void setTenantCode(String tenantCode) {
this.tenantCode = tenantCode;
}
private UUID tenantId;
public UUID getTenantId() {
return tenantId;
}
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
}
@Autowired
public TenantByIdCacheService(TenantByIdCacheOptions options) {
super(options);
}
@EventListener
public void handleTenantTouchedEvent(TenantTouchedEvent event) {
if (event.getTenantId() != null)
this.evict(this.buildKey(event.getTenantId()));
}
@Override
protected Class<TenantByIdCacheValue> valueClass() {
return TenantByIdCacheValue.class;
}
@Override
public String keyOf(TenantByIdCacheValue value) {
return this.buildKey(value.getTenantId());
}
public String buildKey(UUID id) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$tenantId$", id.toString().toLowerCase(Locale.ROOT));
return this.generateKey(keyParts);
}
}

View File

@ -1,183 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.annotation.authorization.Permission;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.TenantEntityManager;
import gr.cite.annotation.data.TenantUserEntity;
import gr.cite.annotation.data.UserEntity;
import gr.cite.annotation.data.tenant.TenantScopedBaseEntity;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.annotation.query.utils.BuildSubQueryInput;
import gr.cite.annotation.query.utils.QueryUtilsService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.hibernate.Session;
import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import javax.management.InvalidApplicationException;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
@Component
public class TenantInterceptor implements WebRequestInterceptor {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantInterceptor.class));
private final TenantScope tenantScope;
private final UserScope userScope;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final ClaimExtractor claimExtractor;
private final ApplicationContext applicationContext;
private final TenantScopeProperties tenantScopeProperties;
private final UserAllowedTenantCacheService userAllowedTenantCacheService;
private final ErrorThesaurusProperties errors;
private final QueryUtilsService queryUtilsService;
public final TenantEntityManager tenantEntityManager;
@PersistenceContext
public EntityManager entityManager;
@Autowired
public TenantInterceptor(
TenantScope tenantScope,
UserScope userScope,
CurrentPrincipalResolver currentPrincipalResolver,
ClaimExtractor claimExtractor,
ApplicationContext applicationContext,
TenantScopeProperties tenantScopeProperties,
UserAllowedTenantCacheService userAllowedTenantCacheService,
ErrorThesaurusProperties errors, QueryUtilsService queryUtilsService, TenantEntityManager tenantEntityManager) {
this.tenantScope = tenantScope;
this.userScope = userScope;
this.currentPrincipalResolver = currentPrincipalResolver;
this.claimExtractor = claimExtractor;
this.applicationContext = applicationContext;
this.tenantScopeProperties = tenantScopeProperties;
this.userAllowedTenantCacheService = userAllowedTenantCacheService;
this.errors = errors;
this.queryUtilsService = queryUtilsService;
this.tenantEntityManager = tenantEntityManager;
}
@Override
public void preHandle(@NotNull WebRequest request) throws InvalidApplicationException, InterruptedException {
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
if (!this.tenantScope.isMultitenant()) return;
boolean isAllowedNoTenant = this.applicationContext.getBean(AuthorizationService.class).authorize(Permission.AllowNoTenant);
if (tenantScope.isSet() && this.entityManager != null) {
List<String> currentPrincipalTenantCodes = this.claimExtractor.asStrings(this.currentPrincipalResolver.currentPrincipal(), ClaimNames.TenantCodesClaimName);
if ((currentPrincipalTenantCodes == null || !currentPrincipalTenantCodes.contains(tenantScope.getTenantCode())) && !isAllowedNoTenant) {
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
}
boolean isUserAllowedTenant = false;
if (this.tenantScope.isDefaultTenant()){
isUserAllowedTenant = true;
} else {
UserAllowedTenantCacheService.UserAllowedTenantCacheValue cacheValue = this.userAllowedTenantCacheService.lookup(this.userAllowedTenantCacheService.buildKey(this.userScope.getUserId(), this.tenantScope.getTenant()));
if (cacheValue != null) {
isUserAllowedTenant = cacheValue.isAllowed();
} else {
isUserAllowedTenant = this.isUserAllowedTenant();
this.userAllowedTenantCacheService.put(new UserAllowedTenantCacheService.UserAllowedTenantCacheValue(this.userScope.getUserId(), this.tenantScope.getTenant(), isUserAllowedTenant));
}
}
if (isUserAllowedTenant) {
this.tenantEntityManager.reloadTenantFilters();
} else {
if (isAllowedNoTenant || this.isWhiteListedEndpoint(request)) {
tenantScope.setTenant(null, null);
} else {
logger.warn("tenant not allowed {}", this.tenantScope.getTenant());
throw new MyForbiddenException(this.errors.getTenantNotAllowed().getCode(), this.errors.getTenantNotAllowed().getMessage());
}
}
} else {
if (!isAllowedNoTenant) {
if (!this.isWhiteListedEndpoint(request)) {
logger.warn("tenant scope not provided");
throw new MyForbiddenException(this.errors.getMissingTenant().getCode(), this.errors.getMissingTenant().getMessage());
}
}
}
}
private boolean isWhiteListedEndpoint(WebRequest request) {
String servletPath = ((ServletWebRequest) request).getRequest().getServletPath();
if (this.tenantScopeProperties.getWhiteListedEndpoints() != null) {
for (String whiteListedEndpoint : this.tenantScopeProperties.getWhiteListedEndpoints()) {
if (servletPath.toLowerCase(Locale.ROOT).startsWith(whiteListedEndpoint.toLowerCase(Locale.ROOT))) {
return true;
}
}
}
return false;
}
private boolean isUserAllowedTenant() throws InvalidApplicationException, InterruptedException {
if (userScope.isSet()) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<UserEntity> query = criteriaBuilder.createQuery(UserEntity.class);
Root<UserEntity> root = query.from(UserEntity.class);
query.where(criteriaBuilder.and(
criteriaBuilder.equal(root.get(UserEntity._isActive), IsActive.Active),
criteriaBuilder.in(root.get(UserEntity._id)).value(queryUtilsService.buildSubQuery(new BuildSubQueryInput<>(new BuildSubQueryInput.Builder<>(TenantUserEntity.class, UUID.class)
.query(query)
.criteriaBuilder(criteriaBuilder)
.keyPathFunc((subQueryRoot) -> subQueryRoot.get(TenantUserEntity._userId))
.filterFunc((subQueryRoot, cb) ->
{
try {
return cb.and(
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._tenantId), this.tenantScope.getTenant()),
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._userId), this.userScope.getUserId()),
criteriaBuilder.equal(subQueryRoot.get(TenantUserEntity._isActive), IsActive.Active)
);
} catch (InvalidApplicationException e) {
throw new RuntimeException(e);
}
}
)
))
)
));
query.multiselect(root.get(UserEntity._id).alias(UserEntity._id));
List<UserEntity> results = this.entityManager.createQuery(query).getResultList();
return !results.isEmpty();
}
return false;
}
@Override
public void postHandle(@NonNull WebRequest request, ModelMap model) {
this.tenantScope.setTenant(null, null);
this.tenantEntityManager.disableTenantFilters();
}
@Override
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
}
}

View File

@ -1,184 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.TenantEntity;
import gr.cite.annotation.errorcode.ErrorThesaurusProperties;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.MyPrincipal;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import javax.management.InvalidApplicationException;
import java.util.List;
import java.util.UUID;
@Component
public class TenantScopeClaimInterceptor implements WebRequestInterceptor {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScopeClaimInterceptor.class));
private final TenantScope tenantScope;
private final ConventionService conventionService;
private final TenantScopeProperties tenantScopeProperties;
private final ErrorThesaurusProperties errorThesaurusProperties;
private final ClaimExtractor claimExtractor;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final String clientTenantClaimName;
private final ClaimExtractorContext claimExtractorContext;
private final TenantByCodeCacheService tenantByCodeCacheService;
private final TenantByIdCacheService tenantByIdCacheService;
@PersistenceContext
public EntityManager entityManager;
@Autowired
public TenantScopeClaimInterceptor(
TenantScope tenantScope,
ConventionService conventionService,
ClaimExtractor claimExtractor,
CurrentPrincipalResolver currentPrincipalResolver,
ErrorThesaurusProperties errorThesaurusProperties,
TenantScopeProperties tenantScopeProperties,
ClaimExtractorContext claimExtractorContext,
TenantByCodeCacheService tenantByCodeCacheService,
TenantByIdCacheService tenantByIdCacheService
) {
this.tenantScope = tenantScope;
this.conventionService = conventionService;
this.currentPrincipalResolver = currentPrincipalResolver;
this.claimExtractor = claimExtractor;
this.errorThesaurusProperties = errorThesaurusProperties;
this.tenantScopeProperties = tenantScopeProperties;
this.claimExtractorContext = claimExtractorContext;
this.tenantByCodeCacheService = tenantByCodeCacheService;
this.tenantByIdCacheService = tenantByIdCacheService;
this.clientTenantClaimName = this.tenantScopeProperties.getClientClaimsPrefix() + ClaimNames.TenantClaimName;
}
@Override
public void preHandle(@NotNull WebRequest request) throws InvalidApplicationException {
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
if (!this.tenantScope.isMultitenant()) return;
MyPrincipal principal = this.currentPrincipalResolver.currentPrincipal();
if (principal != null && principal.isAuthenticated() /* principal.Claims.Any() */) {
boolean scoped = this.scopeByPrincipal(principal);
if (!scoped) scoped = this.scopeByClient(principal);
if (!scoped && this.tenantScope.isSet() && this.tenantScopeProperties.getEnforceTrustedTenant())
throw new MyForbiddenException(this.errorThesaurusProperties.getMissingTenant().getCode(), this.errorThesaurusProperties.getMissingTenant().getMessage());
}
}
private boolean scopeByPrincipal(MyPrincipal principal) {
String tenantCode = this.claimExtractor.tenantString(principal);
if (this.conventionService.isNullOrEmpty(tenantCode)) tenantCode = this.claimExtractor.asString(principal, this.clientTenantClaimName);
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return false;
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
logger.debug("parsed tenant header and set tenant to default tenant");
this.tenantScope.setTenant(null, tenantCode);
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
return true;
}
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
if (tenantId == null) {
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
if (cacheValue != null) {
tenantId = cacheValue.getTenantId();
} else {
tenantId = this.getTenantIdFromDatabase(tenantCode);
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
}
} else {
logger.debug("tenant claim was set to {}", tenantId);
TenantByIdCacheService.TenantByIdCacheValue cacheValue = this.tenantByIdCacheService.lookup(this.tenantByIdCacheService.buildKey(tenantId));
if (cacheValue != null) {
tenantCode = cacheValue.getTenantCode();
} else {
tenantCode = this.getTenantCodeFromDatabase(tenantId);
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
}
}
if (tenantId != null) {
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
this.tenantScope.setTenant(tenantId, tenantCode);
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
return true;
}
return false;
}
private boolean scopeByClient(MyPrincipal principal) throws InvalidApplicationException {
String client = this.claimExtractor.client(principal);
Boolean isWhiteListed = this.tenantScopeProperties.getWhiteListedClients() != null && !this.conventionService.isNullOrEmpty(client) && this.tenantScopeProperties.getWhiteListedClients().contains(client);
logger.debug("client is whitelisted : {}, scope is set: {}, with value {}", isWhiteListed, this.tenantScope.isSet(), (this.tenantScope.isSet() ? this.tenantScope.getTenant() : null));
return isWhiteListed && this.tenantScope.isSet();
}
private UUID getTenantIdFromDatabase(String tenantCode) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
Root<TenantEntity> root = query.from(TenantEntity.class);
query = query.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(TenantEntity._code), tenantCode),
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
)
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
if (results.size() == 1) {
return results.getFirst().getId();
}
return null;
}
private String getTenantCodeFromDatabase(UUID tenantId) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
Root<TenantEntity> root = query.from(TenantEntity.class);
query = query.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(TenantEntity._id), tenantId),
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
)
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
if (results.size() == 1) {
return results.getFirst().getCode();
}
return null;
}
@Override
public void postHandle(@NonNull WebRequest request, ModelMap model) {
this.tenantScope.setTenant(null, null);
this.claimExtractorContext.removeReplaceParameter(TenantScope.TenantReplaceParameter);
}
@Override
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
}
}

View File

@ -1,9 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(TenantScopeProperties.class)
public class TenantScopeConfiguration {
}

View File

@ -1,146 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.authorization.ClaimNames;
import gr.cite.annotation.common.enums.IsActive;
import gr.cite.annotation.common.scope.tenant.TenantScope;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.data.TenantEntity;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractorContext;
import gr.cite.tools.logging.LoggerService;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.jetbrains.annotations.NotNull;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import java.util.List;
import java.util.UUID;
@Component
public class TenantScopeHeaderInterceptor implements WebRequestInterceptor {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(TenantScopeHeaderInterceptor.class));
private final TenantScope tenantScope;
private final ConventionService conventionService;
private final TenantByCodeCacheService tenantByCodeCacheService;
private final TenantByIdCacheService tenantByIdCacheService;
private final ClaimExtractorContext claimExtractorContext;
private final CurrentPrincipalResolver currentPrincipalResolver;
@PersistenceContext
public EntityManager entityManager;
@Autowired
public TenantScopeHeaderInterceptor(
TenantScope tenantScope,
ConventionService conventionService,
TenantByCodeCacheService tenantByCodeCacheService,
TenantByIdCacheService tenantByIdCacheService,
ClaimExtractorContext claimExtractorContext,
CurrentPrincipalResolver currentPrincipalResolver
) {
this.tenantScope = tenantScope;
this.conventionService = conventionService;
this.tenantByCodeCacheService = tenantByCodeCacheService;
this.tenantByIdCacheService = tenantByIdCacheService;
this.claimExtractorContext = claimExtractorContext;
this.currentPrincipalResolver = currentPrincipalResolver;
}
@Override
public void preHandle(@NotNull WebRequest request) {
if (!this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) return;
if (!this.tenantScope.isMultitenant()) return;
String tenantCode = request.getHeader(ClaimNames.TenantClaimName);
logger.debug("retrieved request tenant header is: {}", tenantCode);
if (tenantCode == null || this.conventionService.isNullOrEmpty(tenantCode)) return;
if (tenantCode.equalsIgnoreCase(this.tenantScope.getDefaultTenantCode())){
logger.debug("parsed tenant header and set tenant to default tenant");
this.tenantScope.setTenant(null, tenantCode);
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
return;
}
UUID tenantId = this.conventionService.parseUUIDSafe(tenantCode);
if (tenantId == null) {
TenantByCodeCacheService.TenantByCodeCacheValue cacheValue = this.tenantByCodeCacheService.lookup(this.tenantByCodeCacheService.buildKey(tenantCode));
if (cacheValue != null) {
tenantId = cacheValue.getTenantId();
} else {
tenantId = this.getTenantIdFromDatabase(tenantCode);
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
}
} else {
TenantByIdCacheService.TenantByIdCacheValue cacheValue = this.tenantByIdCacheService.lookup(this.tenantByIdCacheService.buildKey(tenantId));
if (cacheValue != null) {
tenantCode = cacheValue.getTenantCode();
} else {
tenantCode = this.getTenantCodeFromDatabase(tenantId);
this.tenantByCodeCacheService.put(new TenantByCodeCacheService.TenantByCodeCacheValue(tenantCode, tenantId));
this.tenantByIdCacheService.put(new TenantByIdCacheService.TenantByIdCacheValue(tenantCode, tenantId));
}
}
if (tenantId != null) {
logger.debug("parsed tenant header and set tenant id to {}", tenantId);
this.tenantScope.setTenant(tenantId, tenantCode);
this.claimExtractorContext.putReplaceParameter(TenantScope.TenantReplaceParameter, tenantCode);
}
}
private UUID getTenantIdFromDatabase(String tenantCode) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
Root<TenantEntity> root = query.from(TenantEntity.class);
query = query.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(TenantEntity._code), tenantCode),
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
)
).multiselect(root.get(TenantEntity._id).alias(TenantEntity._id));
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
if (results.size() == 1) {
return results.getFirst().getId();
}
return null;
}
private String getTenantCodeFromDatabase(UUID tenantId) {
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<TenantEntity> query = criteriaBuilder.createQuery(TenantEntity.class);
Root<TenantEntity> root = query.from(TenantEntity.class);
query = query.where(
criteriaBuilder.and(
criteriaBuilder.equal(root.get(TenantEntity._id), tenantId),
criteriaBuilder.equal(root.get(TenantEntity._isActive), IsActive.Active)
)
).multiselect(root.get(TenantEntity._code).alias(TenantEntity._code));
List<TenantEntity> results = this.entityManager.createQuery(query).getResultList();
if (results.size() == 1) {
return results.getFirst().getCode();
}
return null;
}
@Override
public void postHandle(@NonNull WebRequest request, ModelMap model) {
this.tenantScope.setTenant(null, null);
this.claimExtractorContext.removeReplaceParameter(TenantScope.TenantReplaceParameter);
}
@Override
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
}
}

View File

@ -1,44 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.HashSet;
import java.util.List;
@ConfigurationProperties(prefix = "tenant.interceptor")
public class TenantScopeProperties {
private String clientClaimsPrefix;
public String getClientClaimsPrefix() {
return clientClaimsPrefix;
}
public void setClientClaimsPrefix(String clientClaimsPrefix) {
this.clientClaimsPrefix = clientClaimsPrefix;
}
private HashSet<String> whiteListedClients;
public HashSet<String> getWhiteListedClients() {
return whiteListedClients;
}
public void setWhiteListedClients(HashSet<String> whiteListedClients) {
this.whiteListedClients = whiteListedClients;
}
private List<String> whiteListedEndpoints;
public List<String> getWhiteListedEndpoints() {
return whiteListedEndpoints;
}
public void setWhiteListedEndpoints(List<String> whiteListedEndpoints) {
this.whiteListedEndpoints = whiteListedEndpoints;
}
private Boolean enforceTrustedTenant;
public Boolean getEnforceTrustedTenant() {
return enforceTrustedTenant;
}
public void setEnforceTrustedTenant(Boolean enforceTrustedTenant) {
this.enforceTrustedTenant = enforceTrustedTenant;
}
}

View File

@ -1,12 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.user-allowed-tenant")
public class UserAllowedTenantCacheOptions extends CacheOptions {
}

View File

@ -1,91 +0,0 @@
package gr.cite.annotation.web.scope.tenant;
import gr.cite.annotation.event.UserAddedToTenantEvent;
import gr.cite.annotation.event.UserRemovedFromTenantEvent;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Locale;
import java.util.UUID;
@Service
public class UserAllowedTenantCacheService extends CacheService<UserAllowedTenantCacheService.UserAllowedTenantCacheValue> {
public static class UserAllowedTenantCacheValue {
public UserAllowedTenantCacheValue() {
}
public UserAllowedTenantCacheValue(UUID userId, UUID tenantId, boolean isAllowed) {
this.userId = userId;
this.tenantId = tenantId;
this.isAllowed = isAllowed;
}
private UUID userId;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
private UUID tenantId;
public UUID getTenantId() {
return tenantId;
}
public void setTenantId(UUID tenantId) {
this.tenantId = tenantId;
}
private boolean isAllowed;
public boolean isAllowed() {
return isAllowed;
}
public void setAllowed(boolean allowed) {
isAllowed = allowed;
}
}
@Autowired
public UserAllowedTenantCacheService(UserAllowedTenantCacheOptions options) {
super(options);
}
@EventListener
public void handleUserRemovedFromTenantEvent(UserRemovedFromTenantEvent event) {
this.evict(this.buildKey(event.getUserId(), event.getTenantId()));
}
@EventListener
public void handleUserAddedToTenantEvent(UserAddedToTenantEvent event) {
this.evict(this.buildKey(event.getUserId(), event.getTenantId()));
}
@Override
protected Class<UserAllowedTenantCacheValue> valueClass() {
return UserAllowedTenantCacheValue.class;
}
@Override
public String keyOf(UserAllowedTenantCacheValue value) {
return this.buildKey(value.getUserId(), value.getTenantId());
}
public String buildKey(UUID userId, UUID tenantId) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$user_id$", userId.toString().toLowerCase(Locale.ROOT));
keyParts.put("$tenant_id$", tenantId.toString().toLowerCase(Locale.ROOT));
return this.generateKey(keyParts);
}
}

View File

@ -1,81 +0,0 @@
package gr.cite.annotation.web.scope.user;
import gr.cite.annotation.common.scope.user.UserScope;
import gr.cite.annotation.data.UserCredentialEntity;
import gr.cite.annotation.model.UserCredential;
import gr.cite.annotation.query.UserCredentialQuery;
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
import gr.cite.tools.data.query.QueryFactory;
import gr.cite.tools.exception.MyForbiddenException;
import gr.cite.tools.fieldset.BaseFieldSet;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import java.util.UUID;
@Component
public class UserInterceptor implements WebRequestInterceptor {
private final UserScope userScope;
private final ClaimExtractor claimExtractor;
private final CurrentPrincipalResolver currentPrincipalResolver;
private final UserInterceptorCacheService userInterceptorCacheService;
private final QueryFactory queryFactory;
@Autowired
public UserInterceptor(
UserScope userScope,
ClaimExtractor claimExtractor,
CurrentPrincipalResolver currentPrincipalResolver,
UserInterceptorCacheService userInterceptorCacheService,
QueryFactory queryFactory) {
this.userScope = userScope;
this.currentPrincipalResolver = currentPrincipalResolver;
this.claimExtractor = claimExtractor;
this.userInterceptorCacheService = userInterceptorCacheService;
this.queryFactory = queryFactory;
}
@Override
public void preHandle(@NotNull WebRequest request) {
UUID userId = null;
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
if (subjectId == null || subjectId.isBlank()) throw new MyForbiddenException("Empty subjects not allowed");
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
if (cacheValue != null) {
userId = cacheValue.getUserId();
} else {
userId = this.findExistingUserFromDb(subjectId);
if (userId != null) {
cacheValue = new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId);
this.userInterceptorCacheService.put(cacheValue);
}
}
}
this.userScope.setUserId(userId);
}
private UUID findExistingUserFromDb(String subjectId) {
UserCredentialEntity userCredential = this.queryFactory.query(UserCredentialQuery.class).disableTracking().externalIds(subjectId).firstAs(new BaseFieldSet().ensure(UserCredential._user));
if (userCredential != null) {
return userCredential.getUserId();
}
return null;
}
@Override
public void postHandle(@NonNull WebRequest request, ModelMap model) {
this.userScope.setUserId(null);
}
@Override
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
}
}

View File

@ -1,10 +0,0 @@
package gr.cite.annotation.web.scope.user;
import gr.cite.tools.cache.CacheOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.user-by-subject-id")
public class UserInterceptorCacheOptions extends CacheOptions {
}

View File

@ -1,77 +0,0 @@
package gr.cite.annotation.web.scope.user;
import gr.cite.annotation.convention.ConventionService;
import gr.cite.annotation.event.UserCredentialTouchedEvent;
import gr.cite.tools.cache.CacheService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.UUID;
@Service
public class UserInterceptorCacheService extends CacheService<UserInterceptorCacheService.UserInterceptorCacheValue> {
private final ConventionService conventionService;
public static class UserInterceptorCacheValue {
public UserInterceptorCacheValue() {
}
public UserInterceptorCacheValue(String subjectId, UUID userId) {
this.subjectId = subjectId;
this.userId = userId;
}
public String getSubjectId() {
return subjectId;
}
public void setSubjectId(String subjectId) {
this.subjectId = subjectId;
}
private String subjectId;
private UUID userId;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
}
@EventListener
public void handleTenantTouchedEvent(UserCredentialTouchedEvent event) {
if (!this.conventionService.isNullOrEmpty(event.getSubjectId()))
this.evict(this.buildKey(event.getSubjectId()));
}
@Autowired
public UserInterceptorCacheService(UserInterceptorCacheOptions options, ConventionService conventionService){
super(options);
this.conventionService = conventionService;
}
@Override
protected Class<UserInterceptorCacheValue> valueClass() {
return UserInterceptorCacheValue.class;
}
@Override
public String keyOf(UserInterceptorCacheValue value) {
return this.buildKey(value.getSubjectId());
}
public String buildKey(String subject) {
HashMap<String, String> keyParts = new HashMap<>();
keyParts.put("$subject$", subject);
return this.generateKey(keyParts);
}
}

View File

@ -1,18 +0,0 @@
spring:
jackson:
default-property-inclusion: non_null
config:
import: optional:classpath:config/app.env[.properties], optional:file:../config/app.env[.properties],
optional:classpath:config/db.yml[.yml], optional:classpath:config/db-${spring.profiles.active}.yml[.yml], optional:file:../config/db-${spring.profiles.active}.yml[.yml],
optional:classpath:config/permissions.yml[.yml], optional:classpath:config/permissions-${spring.profiles.active}.yml[.yml], optional:file:../config/permissions-${spring.profiles.active}.yml[.yml],
optional:classpath:config/errors.yml[.yml], optional:classpath:config/errors-${spring.profiles.active}.yml[.yml], optional:file:../config/errors-${spring.profiles.active}.yml[.yml],
optional:classpath:config/security.yml[.yml], optional:classpath:config/security-${spring.profiles.active}.yml[.yml], optional:file:../config/security-${spring.profiles.active}.yml[.yml],
optional:classpath:config/server.yml[.yml], optional:classpath:config/server-${spring.profiles.active}.yml[.yml], optional:file:../config/server-${spring.profiles.active}.yml[.yml],
optional:classpath:config/logging.yml[.yml], optional:classpath:config/logging-${spring.profiles.active}.yml[.yml], optional:file:../config/logging-${spring.profiles.active}.yml[.yml],
optional:classpath:config/idpclaims.yml[.yml], optional:classpath:config/idpclaims-${spring.profiles.active}.yml[.yml], optional:file:../config/idpclaims-${spring.profiles.active}.yml[.yml],
optional:classpath:config/cache.yml[.yml], optional:classpath:config/cache-${spring.profiles.active}.yml[.yml], optional:file:../config/cache-${spring.profiles.active}.yml[.yml],
optional:classpath:config/tenant.yml[.yml], optional:classpath:config/tenant-${spring.profiles.active}.yml[.yml], optional:file:../config/tenant-${spring.profiles.active}.yml[.yml],
optional:classpath:config/locale.yml[.yml], optional:classpath:config/locale-${spring.profiles.active}.yml[.yml], optional:file:../config/locale-${spring.profiles.active}.yml[.yml],
optional:classpath:config/cors.yml[.yml], optional:classpath:config/cors-${spring.profiles.active}.yml[.yml], optional:file:../config/cors-${spring.profiles.active}.yml[.yml],
optional:classpath:config/queue.yml[.yml], optional:classpath:config/queue-${spring.profiles.active}.yml[.yml], optional:file:../config/queue-${spring.profiles.active}.yml[.yml],
optional:classpath:config/cipher.yml[.yml], optional:classpath:config/cipher-${spring.profiles.active}.yml[.yml], optional:file:../config/cipher-${spring.profiles.active}.yml[.yml]

View File

@ -1,59 +0,0 @@
cache:
manager:
fallbackToNoOpCache: true
caffeineCaches:
- names: [ apikey ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 600
- names: [ tenantByCode ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 20
- names: [ tenantById ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 20
- names: [ userBySubjectId ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 20
- names: [ userAccessTenant ]
allowNullValues: true
initialCapacity: 100
maximumSize: 500
enableRecordStats: false
expireAfterWriteSeconds: 20
- names: [ "affiliation" ]
allowNullValues: true
initialCapacity: 100
maximumSize: 5000
enableRecordStats: false
expireAfterWriteSeconds: 20
mapCaches:
apiKey:
name: apikey
keyPattern: ant_resolve_$keyhash$:v0
userBySubjectId:
name: userBySubjectId
keyPattern: ant_user_by_subject_$subject$:v0
tenantByCode:
name: tenantByCode
keyPattern: ant_tenant_by_code_$code$:v0
tenantById:
name: tenantById
keyPattern: ant_tenant_by_id_$tenantId$:v0
userAllowedTenant:
name: userAccessTenant
keyPattern: ant_user_access_tenant_$user_id$_$tenant_id$:v0
affiliation:
name: affiliation
keyPattern: ant_affiliation_$entity$_$user$_$type$:v0

View File

@ -1,35 +0,0 @@
cipher-profiles:
profile-map:
configuration-profile-name: "configuration"
queue-profile-name: "queue"
notification-profile-name: "queue"
cipher:
# salted-hash:
# default-o: null
# options: null
symetric-encryption:
default-o: null
options:
configuration:
aes:
key: ${CIPHER_SYMETRIC_ENCRYPTION_CONFIGURATION_AES_KEY:}
iv: ${CIPHER_SYMETRIC_ENCRYPTION_CONFIGURATION_AES_IV:}
queue:
aes:
key: ${CIPHER_SYMETRIC_ENCRYPTION_QUEUE_AES_KEY:}
iv: ${CIPHER_SYMETRIC_ENCRYPTION_QUEUE_AES_IV:}
masking:
default: null
options:
configuration:
character: "*"
clear-begining: 2
clear-ending: 4
at-least-percentage: 70
digital-signature:
default: null
options:
configuration:
certificate-path: null
certificate-password: null

View File

@ -1,3 +0,0 @@
web:
cors:
allowed-origins: [ http://localhost, http://localhost:4200 ]

View File

@ -1,7 +0,0 @@
web:
cors:
enabled: true
allowed-methods: [ HEAD, GET, POST, PUT, DELETE, PATCH ]
allowed-headers: [ Authorization, Cache-Control, Content-Type, Content-Disposition, x-tenant ]
exposed-headers: [ Authorization, Cache-Control, Content-Type, Content-Disposition ]
allow-credentials: false

View File

@ -1,10 +0,0 @@
spring:
datasource:
maxIdle: 10
minIdle: 5
maxActive: 10
jpa:
show-sql: true
properties:
hibernate:
format_sql: false

View File

@ -1,28 +0,0 @@
spring:
jpa:
properties:
org:
hibernate:
flushMode: MANUAL
hibernate:
globally_quoted_identifiers: true
ddl-auto: validate
dialect: org.hibernate.dialect.PostgreSQLDialect
hibernate:
naming:
physical-strategy: gr.cite.annotation.data.namingstrategy.PrefixPhysicalNamingStrategy
implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
datasource:
url: ${DB_CONNECTION_STRING}
username: ${DB_USER}
password: ${DB_PASSWORD}
driver-class-name: org.postgresql.Driver
hikari:
connection-timeout: 30000
minimum-idle: 3
maximum-pool-size: 10
idle-timeout: 600000
max-lifetime: 1800000
naming-strategy:
prefix: ant_

View File

@ -1,52 +0,0 @@
error-thesaurus:
# common errors start with 1..
hash-conflict:
code: 100
message: there is a hash conflict for the item modified. please reload to get the latest changes
forbidden:
code: 101
message: insufficient rights
system-error:
code: 102
message: an unexpected system error occurred
missing-tenant:
code: 103
message: tenant scope not provided
model-validation:
code: 106
message: validation error
tenant-not-allowed:
code: 112
message: tenant not allowed
tenant-tampering:
code: 127
message: Tenant tampering
# annotations&notification errors start with 2..
invalid-api-key:
code: 200
message: provided APIKey not valid
stale-api-key:
code: 201
message: there was a problem authorizing you with your API key. Please try again. Contact the system administrator if the problem persists
sensitive-info:
code: 202
message: you are attempting to access sensitive information. please don't do that
non-person-principal:
code: 203
message: the operation is available only to person users
blocking-consent:
code: 204
message: user consents are not sufficient to complete the operation
single-tenant-configuration-per-type-supported:
code: 205
message: a single tenant configuration entry per config type is supported
incompatible-tenant-configuration-types:
code: 206
message: the provided tenant configuration type is incompatible
missing-totp-token:
code: 207
message: totp token not provided
overlapping-tenant-configuration-notifier-list:
code: 208
message: Overlapping Tenant Configuration Notifier List

View File

@ -1,58 +0,0 @@
idpclient:
claims:
mapping:
Subject:
- type: sub
Name:
- type: name
Client:
- type: client_id
AuthenticationMethod:
- type: amr
NotBefore:
- type: nbf
AuthenticatedAt:
- type: auth_time
ExpiresAt:
- type: exp
Email:
- type: email
Roles:
- type: resource_access
path: dmp_web.roles
- type: tenant_roles
filterBy: "(.*):::TenantCode::"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g1]]"
GlobalRoles:
- type: resource_access
path: dmp_web.roles
TenantRoles:
- type: tenant_roles
filterBy: "(.*):::TenantCode::"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g1]]"
Scope:
- type: scope
AccessToken:
- type: x-access-token
visibility: SENSITIVE
Tenant:
- type: x-tenant
IssuedAt:
- type: iat
Issuer:
- type: iss
Audience:
- type: aud
TokenType:
- type: typ
AuthorizedParty:
- type: azp
Authorities:
- type: authorities
TenantCodes:
- type: tenant_roles
filterBy: "(.*):(.*)"
extractByExpression: "(.*):(.*)"
extractExpressionValue: "[[g2]]"

View File

@ -1,4 +0,0 @@
locale:
timezone: UTC
language: en
culture: en-US

View File

@ -1,2 +0,0 @@
logging:
config: classpath:logging/logback-dev.xml

View File

@ -1,35 +0,0 @@
logging:
context:
request:
requestIdKey: req.id
requestRemoteHostKey: req.remoteHost
requestUriKey: req.requestURI
requestQueryStringKey: req.queryString
requestUrlKey : req.requestURL
requestMethodKey: req.method
requestUserAgentKey: req.userAgent
requestForwardedForKey: req.xForwardedFor
requestSchemeKey: req.scheme
requestRemoteAddressKey: req.remoteAddr
requestRemotePortKey: req.remotePort
requestRemoteUserKey: req.remoteUser
principal:
subjectKey: usr.subject
nameKey: usr.name
clientKey: usr.client
audit:
enable: true
requestRemoteHostKey: req.remoteHost
requestUriKey: req.requestURI
requestQueryStringKey: req.queryString
requestUrlKey : req.requestURL
requestMethodKey: req.method
requestUserAgentKey: req.userAgent
requestForwardedForKey: req.xForwardedFor
requestSchemeKey: req.scheme
requestRemoteAddressKey: req.remoteAddr
requestRemotePortKey: req.remotePort
requestRemoteUserKey: req.remoteUser
principalSubjectKey: usr.subject
principalNameKey: usr.name
principalClientKey: usr.client

View File

@ -1,101 +0,0 @@
permissions:
policies:
DeferredAffiliation:
roles:
- TenantAdmin
- TenantUser
- TenantPlanManager
- TenantConfigManager
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
# Tenants
BrowseTenant:
roles: [ ]
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
EditTenant:
roles: [ ]
clients: [ "opencdmp-api-dev" ]
allowAnonymous: false
allowAuthenticated: false
DeleteTenant:
roles: [ ]
claims: [ ]
clients: [ "opencdmp-api-dev" ]
allowAnonymous: false
allowAuthenticated: false
AllowNoTenant:
roles:
- Admin
- InstallationAdmin
claims: [ ]
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
# Users
BrowseUser:
roles:
- Admin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
EditUser:
roles: [ ]
clients: [ "opencdmp-api-dev" ]
allowAnonymous: false
allowAuthenticated: false
DeleteUser:
roles: [ ]
claims: [ ]
clients: [ "opencdmp-api-dev" ]
allowAnonymous: false
allowAuthenticated: false
#Annotation
BrowseAnnotation:
roles:
- Admin
- TenantAdmin
entityAffiliated: true
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
NewAnnotation:
roles:
- Admin
- TenantAdmin
entityAffiliated: true
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
EditAnnotation:
roles:
- Admin
- TenantAdmin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
DeleteAnnotation:
roles:
- Admin
- TenantAdmin
entityAffiliated: false
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
#Tenant Configuration
BrowseTenantConfiguration:
roles:
- Admin
- TenantAdmin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false
EditTenantConfiguration:
roles:
- Admin
- TenantAdmin
clients: [ ]
allowAnonymous: false
allowAuthenticated: false

View File

@ -1,21 +0,0 @@
queue:
rabbitmq:
enable: true
durable: true
queue: cite_dmp_devel_annotation_inbox_queue
exchange: cite_dmp_devel_queue
listenerEnabled: true
publisherEnabled: true
task:
publisher:
enable: true
options:
exchange: cite_dmp_devel_queue
rabbitmq:
enable: true
listener:
enable: true
options:
exchange: cite_dmp_devel_queue
rabbitmq:
enable: true

View File

@ -1,55 +0,0 @@
spring:
rabbitmq:
host: ${RABBIT_HOST}
port: ${RABBIT_PORT}
username: ${RABBIT_USER}
password: ${RABBIT_PASS}
ssl:
enabled: false
queue:
rabbitmq:
enable: false
appId: ${QUEUE_APP_ID}
durable: null
queue: null
exchange: null
listenerEnabled: true
publisherEnabled: true
#TODO
connection-recovery:
enable: true
network-recovery-interval: 5000
unreachable-recovery-interval: 5000
task:
publisher:
enable: false
options:
exchange: null
annotation-created-topic: annotation.created
rabbitmq:
enable: false
interval-seconds: 3
options:
retry-threashold: 100
retry-delay-step-seconds: 300
max-retry-delay-seconds: 10800
too-old-to-send-seconds: 604800
confirm-timeout-seconds: 30
listener:
enable: false
options:
exchange: null
tenant-removal-topic: tenant.remove
tenant-touch-topic: tenant.touch
user-removal-topic: user.remove
user-touch-topic: user.touch
annotation-entities-touch-topic: annotation.entities.touch
annotation-entities-removal-topic: annotation.entities.remove
rabbitmq:
enable: false
interval-seconds: 3
options:
retry-threashold: 100
retry-delay-step-seconds: 300
max-retry-delay-seconds: 10800
too-old-to-send-seconds: 604800

View File

@ -1,6 +0,0 @@
web:
security:
idp:
resource:
jwt:
audiences: [ "dmp_annotation" ]

View File

@ -1,14 +0,0 @@
web:
security:
enabled: true
authorized-endpoints: [ api ]
allowed-endpoints: [ public ]
idp:
api-key:
enabled: false
resource:
token-type: JWT #| opaque
jwt:
claims: [ role, x-role ]
issuer-uri: ${IDP_ISSUER_URI}
validIssuer: ${IDP_ISSUER_URI}

View File

@ -1,2 +0,0 @@
server:
forward-headers-strategy: FRAMEWORK

View File

@ -1,13 +0,0 @@
server:
port: ${WEB_PORT}
forward-headers-strategy: NONE
tomcat:
threads:
max: 20
max-connections: 10000
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB

View File

@ -1,7 +0,0 @@
tenant:
multitenancy:
is-multitenant: true
default-tenant-code: default
interceptor:
client-claims-prefix: client_
enforce-trusted-tenant: false

View File

@ -1,7 +0,0 @@
tenant:
multitenancy:
is-multitenant: false
interceptor:
white-listed-clients: [ ]
enforce-trusted-tenant: false
white-listed-endpoints: [ '/api/annotation/principal/me' ]

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%date{ISO8601} [%thread] %-5level %logger{36} [%X{req.id}] - %message%n</Pattern>
</encoder>
</appender>
<appender name="TROUBLESHOOTING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/logging.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/logging.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%date{ISO8601} [%thread] %-5level %logger{36} [%X{req.id}] - %message%n</Pattern>
</encoder>
</appender>
<appender name="AUDITING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/auditing.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/auditing.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>15</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>%date{ISO8601} - %X{req.id} - %message%n</Pattern>
</encoder>
</appender>
<logger name="org.springframework.web" level="INFO" additivity="false">
<appender-ref ref="TROUBLESHOOTING"/>
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.hibernate" level="INFO" additivity="false">
<appender-ref ref="TROUBLESHOOTING"/>
<appender-ref ref="STDOUT"/>
</logger>
<logger name="gr.cite" level="DEBUG" additivity="false">
<appender-ref ref="TROUBLESHOOTING"/>
<appender-ref ref="STDOUT"/>
</logger>
<logger name="audit" level="INFO" additivity="false">
<appender-ref ref="AUDITING"/>
<appender-ref ref="STDOUT"/>
</logger>
<root level="info">
<appender-ref ref="TROUBLESHOOTING"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

View File

@ -1,10 +0,0 @@
validation.empty=Value cannot be empty
validation.hashempty=Hash must be set
validation.lowerthanmin=Value must be larger than {value}
validation.largerthanmax=Value must be less than {value}
validation.invalidid=Not valid id
General_ItemNotFound=Item {0} of type {1} not found
Validation_Required={0} is required
Validation_OverPosting=Too much info
Validation_MaxLength={0} too long
Validation_UnexpectedValue=Unexpected value in field {0}

View File

@ -1,6 +0,0 @@
validation.empty=el-Value cannot be empty
validation.hashempty=el-Hash must be set
validation.lowerthanmin=el-Value must be larger than {value}
validation.largerthanmax=el-Value must be less than {value}
validation.invalidid=el-Not valid id
General_ItemNotFound=el-Item {0} of type {1} not found

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