Compare commits
94 Commits
dmp-refact
...
master
Author | SHA1 | Date |
---|---|---|
Diamantis Tziotzios | e8aef281d4 | |
Diamantis Tziotzios | 00c6978594 | |
Diamantis Tziotzios | 3adb518e61 | |
Konstantina Galouni | eb74ef86b9 | |
Diamantis Tziotzios | a1ee9c82bc | |
Diamantis Tziotzios | 5e5bd39313 | |
Diamantis Tziotzios | 5e99cef60e | |
Diamantis Tziotzios | cc7edc2f49 | |
Diamantis Tziotzios | a1849c64ca | |
Diamantis Tziotzios | 192220161b | |
George Kalampokis | 87758c3e9a | |
Diamantis Tziotzios | 83342f5afa | |
Diamantis Tziotzios | 65cdb3b6ea | |
Diamantis Tziotzios | 536ba9b900 | |
Alexandros Mandilaras | 6bd3302788 | |
Diamantis Tziotzios | 4970f5812f | |
Diamantis Tziotzios | 9fed92dbcb | |
Diamantis Tziotzios | 44dab9c19a | |
Alexandros Mandilaras | 54f911d826 | |
Diamantis Tziotzios | 9879050eab | |
Diamantis Tziotzios | 8a41a7dcd9 | |
Diamantis Tziotzios | d60cc144d5 | |
Georgios Kakaletris | 9c37e5a073 | |
Georgios Kakaletris | 444c1aacb1 | |
Diamantis Tziotzios | 59d7383947 | |
Diamantis Tziotzios | 6caa1af134 | |
George Kalampokis | 74a6019a72 | |
George Kalampokis | 5c903c0f48 | |
George Kalampokis | ec8f6a6d48 | |
Bernaldo Mihasi | ecd86f413a | |
Bernaldo Mihasi | c238615b50 | |
Bernaldo Mihasi | 10d0f1fb0e | |
Bernaldo Mihasi | 846405435c | |
Bernaldo Mihasi | dfc9e14003 | |
Bernaldo Mihasi | bc1894586b | |
Bernaldo Mihasi | 2bf0a857bc | |
Bernaldo Mihasi | 3d10e8ad28 | |
Bernaldo Mihasi | 53b61853e1 | |
Bernaldo Mihasi | d644b1dc91 | |
Diamantis Tziotzios | 50c96ef821 | |
Konstantina Galouni | 0adc7044ab | |
Konstantina Galouni | 13e62fd409 | |
Diamantis Tziotzios | 7185b5d117 | |
George Kalampokis | 5f131b9823 | |
Diamantis Tziotzios | 93320f7c94 | |
Diamantis Tziotzios | 876d99ce38 | |
George Kalampokis | 7a71110033 | |
Diamantis Tziotzios | 14c267c97e | |
Diamantis Tziotzios | b04b35d62b | |
Diamantis Tziotzios | 7a8375b988 | |
Diamantis Tziotzios | 895dbcf098 | |
Diamantis Tziotzios | bd15b1e2c7 | |
George Kalampokis | faabd343a9 | |
George Kalampokis | e5a929f259 | |
George Kalampokis | d1fc10854c | |
George Kalampokis | 2537923dc0 | |
George Kalampokis | c1adbe283a | |
George Kalampokis | 1c365a191e | |
Kristian Ntavidi | 82c5586067 | |
George Kalampokis | 04f230dff1 | |
George Kalampokis | 72d88d9db4 | |
George Kalampokis | 143a4c0214 | |
George Kalampokis | e7e5ed02b3 | |
George Kalampokis | b5fcc5971e | |
Diamantis Tziotzios | c16c35225f | |
Diamantis Tziotzios | f5d266554b | |
Diamantis Tziotzios | db31597fc0 | |
Diamantis Tziotzios | 9f5054668e | |
George Kalampokis | 38986ef67b | |
Diamantis Tziotzios | bff260b85b | |
George Kalampokis | 9519300dc4 | |
George Kalampokis | 9373d3e038 | |
dtziotzios | d971f02a94 | |
Georgios Kakaletris | d3915e26e7 | |
George Kalampokis | c028aad615 | |
Diamantis Tziotzios | 4ee39074a3 | |
Diamantis Tziotzios | 1b4952a909 | |
Diamantis Tziotzios | 3ada5a0d3d | |
Diamantis Tziotzios | 63ee865dd9 | |
Diamantis Tziotzios | 2a52138124 | |
Diamantis Tziotzios | 7cf64c18f2 | |
Diamantis Tziotzios | 71d317bab7 | |
Ioannis Kalyvas | cd8b3448f5 | |
Ioannis Kalyvas | c3d4cb6fdd | |
Ioannis Kalyvas | b0ccac191f | |
Ioannis Kalyvas | 3b1f37ef22 | |
Ioannis Kalyvas | b8e040ee94 | |
Ioannis Kalyvas | 50444a0b73 | |
Diamantis Tziotzios | 85bdb7fad1 | |
annabakouli | b2e49fbb8a | |
Diamantis Tziotzios | bfc6b63067 | |
Nikolaos Laskaris | 9941c96dc2 | |
Nikolaos Laskaris | 06272c79da | |
Nikolaos Laskaris | a00eec68d8 |
|
@ -0,0 +1,5 @@
|
|||
PROFILE=docker
|
||||
|
||||
# Version of Elastic products
|
||||
ELK_VERSION=7.17.4
|
||||
STACK_VERSION=7.17.4
|
|
@ -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/
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
# Declare files that will always have LF line endings on checkout.
|
||||
*.sh text eol=lf
|
|
@ -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.
|
|
@ -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)
|
|
@ -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:
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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>
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
TAG=6.3.1
|
||||
ELASTIC_VERSION=6.3.1
|
||||
ELASTIC_PASSWORD=changeme
|
|
@ -0,0 +1 @@
|
|||
**/*~
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
language: python
|
||||
python: ['3.5']
|
||||
script: make
|
||||
|
||||
sudo: required
|
||||
services: ['docker']
|
|
@ -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.
|
|
@ -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=%)
|
|
@ -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`.
|
|
@ -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}"
|
||||
}
|
||||
}
|
|
@ -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 |
|
@ -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}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!/.gitignore
|
|
@ -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%
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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:
|
|
@ -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
|
|
@ -0,0 +1,14 @@
|
|||
input {
|
||||
beats {
|
||||
port => 31312
|
||||
ssl => false
|
||||
client_inactivity_timeout => 3000
|
||||
}
|
||||
}
|
||||
|
||||
filter {
|
||||
}
|
||||
|
||||
output {
|
||||
pipeline { send_to => open_dmp_main }
|
||||
}
|
|
@ -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 }
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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"]
|
|
@ -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'
|
|
@ -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/
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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++);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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]
|
|
@ -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
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
web:
|
||||
cors:
|
||||
allowed-origins: [ http://localhost, http://localhost:4200 ]
|
|
@ -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
|
|
@ -1,10 +0,0 @@
|
|||
spring:
|
||||
datasource:
|
||||
maxIdle: 10
|
||||
minIdle: 5
|
||||
maxActive: 10
|
||||
jpa:
|
||||
show-sql: true
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: false
|
|
@ -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_
|
|
@ -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¬ification 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
|
|
@ -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]]"
|
|
@ -1,4 +0,0 @@
|
|||
locale:
|
||||
timezone: UTC
|
||||
language: en
|
||||
culture: en-US
|
|
@ -1,2 +0,0 @@
|
|||
logging:
|
||||
config: classpath:logging/logback-dev.xml
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,6 +0,0 @@
|
|||
web:
|
||||
security:
|
||||
idp:
|
||||
resource:
|
||||
jwt:
|
||||
audiences: [ "dmp_annotation" ]
|
|
@ -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}
|
|
@ -1,2 +0,0 @@
|
|||
server:
|
||||
forward-headers-strategy: FRAMEWORK
|
|
@ -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
|
|
@ -1,7 +0,0 @@
|
|||
tenant:
|
||||
multitenancy:
|
||||
is-multitenant: true
|
||||
default-tenant-code: default
|
||||
interceptor:
|
||||
client-claims-prefix: client_
|
||||
enforce-trusted-tenant: false
|
|
@ -1,7 +0,0 @@
|
|||
tenant:
|
||||
multitenancy:
|
||||
is-multitenant: false
|
||||
interceptor:
|
||||
white-listed-clients: [ ]
|
||||
enforce-trusted-tenant: false
|
||||
white-listed-endpoints: [ '/api/annotation/principal/me' ]
|
|
@ -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>
|
|
@ -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}
|
|
@ -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
Loading…
Reference in New Issue