Compare commits
343 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fdd957e9e | ||
|
|
18de1e52f5 | ||
|
|
00ef5f67a1 | ||
|
|
74b289b38c | ||
|
|
100b1c4cc1 | ||
|
|
f96adb2097 | ||
|
|
4e43e4e255 | ||
|
|
7bb15fe456 | ||
|
|
a169fb585c | ||
|
|
af38bb2f29 | ||
|
|
f25253cb3b | ||
|
|
ad7035d7cf | ||
|
|
dfa4009b84 | ||
|
|
4eefde9ff6 | ||
|
|
45f6386104 | ||
|
|
db495d17b3 | ||
|
|
e0a1df09ab | ||
|
|
93e3315a8a | ||
|
|
5e3d632846 | ||
|
|
6412b50ff9 | ||
|
|
4e4a8d7089 | ||
|
|
e2f84d9bbf | ||
|
|
09a86f0a23 | ||
|
|
8adeb37275 | ||
|
|
6968f94e6e | ||
|
|
01731bb7a4 | ||
|
|
47ffe83b8f | ||
|
|
b3757876a7 | ||
|
|
dddf2ba3d1 | ||
|
|
38bbb71965 | ||
|
|
014e82e9b3 | ||
|
|
f5f08b215e | ||
|
|
a540524d52 | ||
|
|
8cba143c76 | ||
|
|
5e0a363aff | ||
|
|
26525d4baa | ||
|
|
c6ea2430bb | ||
|
|
f88dd799b0 | ||
|
|
f4555e1737 | ||
|
|
50e6178060 | ||
|
|
25b2db376b | ||
|
|
0cba921ce2 | ||
|
|
ce8cfff69e | ||
|
|
2c2f3464e9 | ||
|
|
eaa70cffb1 | ||
|
|
6bbe3316ac | ||
|
|
3f94e66eda | ||
|
|
114fbfc62f | ||
|
|
d3e575159f | ||
|
|
5e7dcb1689 | ||
|
|
f9668a3c07 | ||
|
|
aa9fe087f5 | ||
|
|
310339a5d9 | ||
|
|
23c3b6787e | ||
|
|
ae21409577 | ||
|
|
ae04a6fd74 | ||
|
|
d5b2cb2af2 | ||
|
|
e71712450d | ||
|
|
f0b484895a | ||
|
|
c303d46d8e | ||
|
|
8ed4e8660f | ||
|
|
119676e143 | ||
|
|
7b135dc48b | ||
|
|
0692ac8309 | ||
|
|
bacb43c9db | ||
|
|
c2b14d176c | ||
|
|
c7098c98ac | ||
|
|
ed86367ab8 | ||
|
|
8399251f44 | ||
|
|
039b0fad13 | ||
|
|
537dc185a3 | ||
|
|
258bf63cd0 | ||
|
|
1149a0809e | ||
|
|
534ace6a55 | ||
|
|
1c7698d2de | ||
|
|
a2cd372d51 | ||
|
|
628eda60b9 | ||
|
|
534af6d061 | ||
|
|
50bfc103b6 | ||
|
|
b9121b839b | ||
|
|
53e49f083d | ||
|
|
20c0890ad0 | ||
|
|
a689835af6 | ||
|
|
cd159879f5 | ||
|
|
14d9bfcb3b | ||
|
|
9bdd2bb09a | ||
|
|
e3e01c8dbd | ||
|
|
5bda827c21 | ||
|
|
e821371806 | ||
|
|
828c8a840c | ||
|
|
8a7b861ceb | ||
|
|
112d38d7be | ||
|
|
2f49ee0908 | ||
|
|
6f70d1e333 | ||
|
|
6dc5dc6142 | ||
|
|
087431678a | ||
|
|
1107f91691 | ||
|
|
99641a6688 | ||
|
|
12e8c0f53f | ||
|
|
715d33b9e1 | ||
|
|
f98394c136 | ||
|
|
0ae6b2a77b | ||
|
|
b35386684e | ||
|
|
af37030c68 | ||
|
|
6954a5cee3 | ||
|
|
7bec8f98e6 | ||
|
|
5af289479e | ||
|
|
af16b4db01 | ||
|
|
68bc112660 | ||
|
|
b3dd62e3ca | ||
|
|
ac1b86fa41 | ||
|
|
abb11a4893 | ||
|
|
9241a191fa | ||
|
|
1e0fbd8e1d | ||
|
|
5c0679f1fc | ||
|
|
1272d91e74 | ||
|
|
72def10e4a | ||
|
|
2d34c1999d | ||
|
|
f0f888a63d | ||
|
|
7f220bd348 | ||
|
|
86e676cc51 | ||
|
|
a20484e486 | ||
|
|
d151831ad9 | ||
|
|
e2c74b607b | ||
|
|
a54d08bcb0 | ||
|
|
2fc8c9fc65 | ||
|
|
631fe2bc1f | ||
|
|
cb88dca0ea | ||
|
|
c0b98a1bef | ||
|
|
dc2a11ac83 | ||
|
|
b5a76fd483 | ||
|
|
fa71cb9633 | ||
|
|
8f8b6787e9 | ||
|
|
6493c75de4 | ||
|
|
a6c97df229 | ||
|
|
84a0c47ae6 | ||
|
|
d0b6081000 | ||
|
|
f4b874c5a4 | ||
|
|
2648d49c81 | ||
|
|
5583f6613d | ||
|
|
4eb7e1709e | ||
|
|
b43cc69633 | ||
|
|
6712f25890 | ||
|
|
9838dcf10a | ||
|
|
44a404f2da | ||
|
|
2d31712295 | ||
|
|
2feffb9b80 | ||
|
|
4a2203893c | ||
|
|
7f45a73bce | ||
|
|
95778f7926 | ||
|
|
d74d4217f8 | ||
|
|
0722b50584 | ||
|
|
51d1039866 | ||
|
|
819730d970 | ||
|
|
64cecc4a7d | ||
|
|
96d03f756d | ||
|
|
8783dc91e7 | ||
|
|
10a834e7f8 | ||
|
|
08ed0f29c0 | ||
|
|
93a1b1fcda | ||
|
|
6edbd910c4 | ||
|
|
d39ca21c4b | ||
|
|
1f3c862497 | ||
|
|
79a465aa40 | ||
|
|
d655ea958b | ||
|
|
8a41d70701 | ||
|
|
980c59de78 | ||
|
|
7462b38f9f | ||
|
|
755a6f0798 | ||
|
|
0c66bacb49 | ||
|
|
12fd15390d | ||
|
|
d935a0488e | ||
|
|
55f380a602 | ||
|
|
b0bf8359b9 | ||
|
|
b57a12ce79 | ||
|
|
7ae7dc10db | ||
|
|
7dc03d7781 | ||
|
|
6d24d00a67 | ||
|
|
4bd7e8d09b | ||
|
|
d55ef70442 | ||
|
|
d2e52263fb | ||
|
|
921197a665 | ||
|
|
2692a7b1a9 | ||
|
|
9a94879960 | ||
|
|
6242258e09 | ||
|
|
eebbc2d00d | ||
|
|
362a86916a | ||
|
|
5dcf0dbef0 | ||
|
|
f6916dab3e | ||
|
|
442b12edf9 | ||
|
|
f6a0860ac1 | ||
|
|
c458b8e178 | ||
|
|
3bd9b72b3a | ||
|
|
90c159f52d | ||
|
|
b97bd1d9df | ||
|
|
6435f1814b | ||
|
|
0cd586552c | ||
|
|
8ce5b9bc30 | ||
|
|
c68e4033a3 | ||
|
|
59bd73c980 | ||
|
|
18d982f6c2 | ||
|
|
736e4fd874 | ||
|
|
7559ab64ef | ||
|
|
7cf39a0b68 | ||
|
|
381b30198b | ||
|
|
d48263e189 | ||
|
|
7a57283868 | ||
|
|
68ec498bbe | ||
|
|
bbe6307a9b | ||
|
|
2edecc9915 | ||
|
|
78a455db44 | ||
|
|
1508c8fad4 | ||
|
|
6fbfbb17ce | ||
|
|
979e9069fa | ||
|
|
57aa00e096 | ||
|
|
9ace6e25a5 | ||
|
|
5478bd443e | ||
|
|
87afed5aab | ||
|
|
47d8089a36 | ||
|
|
96fbaf7ec5 | ||
|
|
d23fbc54f8 | ||
|
|
518cc6139f | ||
|
|
9a316d1c9f | ||
|
|
55c82c88a6 | ||
|
|
76235935df | ||
|
|
8a47cd9103 | ||
|
|
30a045364d | ||
|
|
acd8f4369b | ||
|
|
02f8689769 | ||
|
|
1c8a8e6302 | ||
|
|
c2bd9a34f4 | ||
|
|
c2b7a69a08 | ||
|
|
e012af658d | ||
|
|
81dbcb98ed | ||
|
|
e88e76771c | ||
|
|
171922c1a4 | ||
|
|
fc025ae440 | ||
|
|
5869719c15 | ||
|
|
3b29517363 | ||
|
|
dda4a94274 | ||
|
|
d40dd2bd57 | ||
|
|
ab44dae367 | ||
|
|
184031e760 | ||
|
|
76aa088152 | ||
|
|
ba0cbae9c4 | ||
|
|
3f7311b272 | ||
|
|
53fec52f86 | ||
|
|
e5c7dae219 | ||
|
|
cf0f623bd6 | ||
|
|
6bb8ee01b7 | ||
|
|
9d9aa6f46d | ||
|
|
400ced9b39 | ||
|
|
cb8b7a27c6 | ||
|
|
1003f4a4a1 | ||
|
|
e6314a220a | ||
|
|
32d12d4155 | ||
|
|
e66082013b | ||
|
|
8bcd42990e | ||
|
|
92ce09c49d | ||
|
|
e8fe27d6df | ||
|
|
60d603e028 | ||
|
|
2c9a7e06c1 | ||
|
|
d91ae1f261 | ||
|
|
d441a8c5a8 | ||
|
|
8c6d55fe6f | ||
|
|
b2bc62694c | ||
|
|
fc889b04a1 | ||
|
|
e6150888ab | ||
|
|
fefcca2ddf | ||
|
|
3318143bb4 | ||
|
|
f377d1a3ab | ||
|
|
d7f0899c3b | ||
|
|
98c6f27190 | ||
|
|
c0b897112a | ||
|
|
d74dab8fef | ||
|
|
791b6b76da | ||
|
|
2d10b2b5c6 | ||
|
|
c904e5947c | ||
|
|
a79165bb09 | ||
|
|
550c05e93b | ||
|
|
cdff7c09cf | ||
|
|
c8860f09f3 | ||
|
|
e0fd3b9133 | ||
|
|
5cea2a7cf2 | ||
|
|
479168b029 | ||
|
|
cef0f2830b | ||
|
|
0fd19a5798 | ||
|
|
9e51a8f5ea | ||
|
|
d99502b762 | ||
|
|
70b9042c54 | ||
|
|
d5a14a5bf3 | ||
|
|
99c3239f70 | ||
|
|
c7b375d13d | ||
|
|
a41dc2a4dd | ||
|
|
dccf84bfa8 | ||
|
|
e7fef6be34 | ||
|
|
757e726339 | ||
|
|
5c61cacef7 | ||
|
|
3b693ebe1a | ||
|
|
000b62ccc7 | ||
|
|
e339d133e0 | ||
|
|
4d1a6295d9 | ||
|
|
c116687aa1 | ||
|
|
74e6c6bf91 | ||
|
|
ecf9477ed8 | ||
|
|
fb72382a66 | ||
|
|
7fc67b2c7e | ||
|
|
016980ee07 | ||
|
|
81ad77fa59 | ||
|
|
858be8c050 | ||
|
|
384d0a1cee | ||
|
|
2b250e336d | ||
|
|
e896b5c808 | ||
|
|
5f3418ad3b | ||
|
|
7266235983 | ||
|
|
04d56f3b47 | ||
|
|
aa619e9012 | ||
|
|
58d53f2647 | ||
|
|
bad1226376 | ||
|
|
8a2f8c0cb1 | ||
|
|
5a21604036 | ||
|
|
fc701ffb04 | ||
|
|
7e28e5574e | ||
|
|
1ede240122 | ||
|
|
fd2add72bc | ||
|
|
7df651880f | ||
|
|
63742620a8 | ||
|
|
44ee097d83 | ||
|
|
0d151108df | ||
|
|
5702e8abab | ||
|
|
e84ee1ae4f | ||
|
|
a1a5741714 | ||
|
|
e58012e4ea | ||
|
|
53b668f469 | ||
|
|
ab6a9e8226 | ||
|
|
4a44114cb4 | ||
|
|
ffb0b282e7 | ||
|
|
aaae453cc6 | ||
|
|
53c5141ea6 | ||
|
|
0808131424 | ||
|
|
7f178f6b45 | ||
|
|
47ca03db93 | ||
|
|
073f4cee2d |
40
.dev/migration/README.md
Normal file
40
.dev/migration/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
### Hot to run locally and test
|
||||
|
||||
1. Start docker compose from this dir
|
||||
2. Start persistence-service with profile: dev
|
||||
* this will create the tenant sync exchange
|
||||
* startup might fail due to tenant-usermanagement not being up. but you need the tenant sync queue first)
|
||||
|
||||
3. Start tenant-user-management with profiles: dev, redaction, migration
|
||||
* this will migrate the master DB and sync KC
|
||||
* it will also send a message to persistence service to run the migration
|
||||
* in case the message doesn't arrive - restart persistence and/or this service - the tenant migration in this service is idempotent
|
||||
|
||||
4. Persistence service should now queue 1869 files to layout-parser
|
||||
5. Start layout-parser with profile: dev
|
||||
6. Start redaction-service with profile: dev
|
||||
7. Debug issues & repeat
|
||||
8. UI is available at htpp://localhost:4200/ui -> login with manageradmin/OsloImWinter!23
|
||||
9. To start clean. docker compose down and up again.
|
||||
|
||||
Useful info:
|
||||
* This docker compose contains a dump from staging from ~2 weeks ago
|
||||
* KC credentials are: admin / secretPasswordForAdmin1234
|
||||
* To use different data you need a tenant-manager database dump from an environment of your choice
|
||||
* this can be obtained via kubectl port forward like so: `kubectl -n <namespace> port-forward services/main-db-postgresql 5432`
|
||||
* followed by a dump: `pg_dumpall -U tenantmanager -h 127.0.0.1 > main.sql`
|
||||
* And a tenant database:
|
||||
* this can be obtained via kubectl port forward like so: `kubectl -n <namespace> port-forward services/tenant-db-postgresql 5432`
|
||||
* followed by a dump: `pg_dumpall -U tenantmanager -h 127.0.0.1 > tenant.sql`
|
||||
* And a KC database:
|
||||
* this can be obtained via kubectl port forward like so: `kubectl -n <namespace> port-forward services/keycloak-postgresql 5432`
|
||||
* followed by a dump: `pg_dumpall -U tenantmanager -h 127.0.0.1 > tenant.sql`
|
||||
* You can now use the migration/utils/database Dockerfile to create a fat DB image with the data ( replace data.sql with your dump and tag accordingly)
|
||||
* For a minio dump you need a similar command ( port fwd sometimes crashes sine clone command uses a lot of connections ):
|
||||
* open port forward `while true; do kubectl -n redaction-staging port-forward statefulset/redaction-staging-minio 9000 --request-timeout=10m; done`
|
||||
* Install mc minio command line utility
|
||||
* create an alias `mc alias set <mirror_name> http://localhost:9000 minioadminuser minioadminpassword`
|
||||
* run: `while true; do mc mirror <mirror_name>/<bucket_name> ./<bucket_name>; done`
|
||||
* use migration/utils/minio/Dockerfile to create an image -> you need to copy it to where the export is.
|
||||
* After you have the images, replace the images in compose with the ones you want
|
||||
|
||||
86
.dev/migration/docker-compose.yaml
Normal file
86
.dev/migration/docker-compose.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
tenant-database:
|
||||
pull_policy: always
|
||||
image: nexus.knecon.com:5001/migration/redtenant-db-staging-multi-arch
|
||||
ports:
|
||||
- 15432:5432
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=r3dact3d
|
||||
- POSTGRES_USER=tenant
|
||||
- POSTGRES_DB=red-tenant
|
||||
main-database:
|
||||
image: nexus.knecon.com:5001/migration/tenantmanager-db-staging-multi-arch
|
||||
pull_policy: always
|
||||
ports:
|
||||
- 25432:5432
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=r3dact3d
|
||||
- POSTGRES_USER=tenantmanager
|
||||
- POSTGRES_DB=tenantmanager
|
||||
keycloak-database:
|
||||
image: nexus.knecon.com:5001/migration/keycloak-db-multi-arch
|
||||
pull_policy: always
|
||||
ports:
|
||||
- 35432:5432
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=some-password
|
||||
- POSTGRES_USER=bn_keycloak
|
||||
- POSTGRES_DB=bitnami_keycloak
|
||||
keycloak:
|
||||
command: ['start']
|
||||
volumes:
|
||||
- /tmp/export:/opt/export
|
||||
depends_on:
|
||||
- "keycloak-database"
|
||||
image: quay.io/keycloak/keycloak:20.0.1
|
||||
environment:
|
||||
JAVA_OPTS_APPEND: -Dkeycloak.profile.feature.upload_scripts=enabled
|
||||
KC_HOSTNAME: localhost
|
||||
KC_HTTP_ENABLED: true
|
||||
KC_HOSTNAME_STRICT_HTTPS: false
|
||||
KC_DB: postgres
|
||||
KC_DB_URL: jdbc:postgresql://keycloak-database:5432/bitnami_keycloak
|
||||
KC_DB_USERNAME: bn_keycloak
|
||||
KC_DB_PASSWORD: some-password
|
||||
ports:
|
||||
- "8080:8080"
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
rabbitmq:
|
||||
image: 'rabbitmq:3.9-alpine'
|
||||
environment:
|
||||
- RABBITMQ_DEFAULT_USER=user
|
||||
- RABBITMQ_DEFAULT_PASS=rabbitmq
|
||||
ports:
|
||||
- 5672:5672
|
||||
- 15672:15672
|
||||
minio:
|
||||
pull_policy: always
|
||||
image: nexus.knecon.com:5001/migration/minio-staging-multi-arch
|
||||
ports:
|
||||
- "9001:9001"
|
||||
- "9000:9000"
|
||||
adminer:
|
||||
image: adminer:latest
|
||||
ports:
|
||||
- "58080:8080"
|
||||
ui:
|
||||
pull_policy: always
|
||||
image: nexus.knecon.com:5001/migration/test-ui-csp
|
||||
environment:
|
||||
API_URL: http://localhost:4200
|
||||
APP_NAME: Local
|
||||
FRONTEND_APP_VERSION: 42
|
||||
OAUTH_URL: http://localhost:8080
|
||||
OAUTH_CLIENT_ID: redaction
|
||||
BASE_TRANSLATIONS_DIRECTORY: /assets/i18n/redact/
|
||||
THEME: redact
|
||||
ports:
|
||||
- "4200:8080"
|
||||
# pg_dump bitnami_keycloak -U bn_keycloak -h 127.0.0.1 -p 35432 > data.sql
|
||||
# pg_dump tenantmanager -U tenantmanager -h 127.0.0.1 -p 25432 > data.sql
|
||||
# pg_dump red-tenant -U tenant -h 127.0.0.1 -p 15432 > data.sql
|
||||
2
.dev/migration/utils/database/Dockerfile
Normal file
2
.dev/migration/utils/database/Dockerfile
Normal file
@ -0,0 +1,2 @@
|
||||
FROM postgres:16.0
|
||||
COPY data.sql /docker-entrypoint-initdb.d/
|
||||
16
.dev/migration/utils/minio/Dockerfile
Normal file
16
.dev/migration/utils/minio/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM docker.io/minio/minio:latest
|
||||
|
||||
COPY ./redaction /tmp/redaction
|
||||
COPY --from=docker.io/minio/mc:latest /usr/bin/mc /usr/bin/mc
|
||||
RUN mkdir /buckets
|
||||
RUN minio server /buckets & \
|
||||
server_pid=$!; \
|
||||
until mc alias set local http://localhost:9000 minioadmin minioadmin; do \
|
||||
sleep 1; \
|
||||
done; \
|
||||
mc mb local/redaction; \
|
||||
mc mirror /tmp/redaction local/redaction; \
|
||||
kill $server_pid
|
||||
RUN rm -Rf /tmp/redaction
|
||||
|
||||
CMD ["minio", "server", "/buckets", "--address", ":9000", "--console-address", ":9001"]
|
||||
8
.dev/tenant-user-management-service/README.md
Normal file
8
.dev/tenant-user-management-service/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Setup
|
||||
start docker-compose
|
||||
login to http://localhost:8080 with admin/admin
|
||||
go to "clients", select "import client" and drag-and-drop manager.json from this folder.
|
||||
Follow import wizard steps.
|
||||
Once done. select the manager client, go to tab "SERVICE ACCOUNT ROLES"
|
||||
Click "assign roles" and assign all roles from "filter by realm roles".
|
||||
|
||||
@ -2,10 +2,11 @@ version: '2'
|
||||
|
||||
services:
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:20.0
|
||||
image: quay.io/keycloak/keycloak:latest
|
||||
command: start-dev
|
||||
environment:
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_IMPORT: master.json
|
||||
KEYCLOAK_ADMIN_PASSWORD: admin
|
||||
ports:
|
||||
- 8080:8080
|
||||
@ -23,7 +24,7 @@ services:
|
||||
POSTGRES_PASSWORD: fforesight
|
||||
POSTGRES_DB: master
|
||||
rabbitmq:
|
||||
image: 'rabbitmq:3.9-alpine'
|
||||
image: 'rabbitmq:3.9-management-alpine'
|
||||
mem_limit: 500m
|
||||
environment:
|
||||
- RABBITMQ_DEFAULT_USER=user
|
||||
@ -31,6 +32,8 @@ services:
|
||||
ports:
|
||||
- 5672:5672
|
||||
- 15672:15672
|
||||
- 5671:5671
|
||||
- 4369:4369
|
||||
minio:
|
||||
mem_limit: 1000m
|
||||
image: minio/minio
|
||||
|
||||
99
.dev/tenant-user-management-service/manager.json
Normal file
99
.dev/tenant-user-management-service/manager.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"clientId": "manager",
|
||||
"name": "manager",
|
||||
"description": "manager",
|
||||
"rootUrl": "",
|
||||
"adminUrl": "",
|
||||
"baseUrl": "",
|
||||
"surrogateAuthRequired": false,
|
||||
"enabled": true,
|
||||
"alwaysDisplayInConsole": false,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "oE2DVrV45w0Tr5jBBcoufVxIkFWU69lP",
|
||||
"redirectUris": [
|
||||
"/*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"/*"
|
||||
],
|
||||
"notBefore": 0,
|
||||
"bearerOnly": false,
|
||||
"consentRequired": false,
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": true,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"serviceAccountsEnabled": true,
|
||||
"authorizationServicesEnabled": true,
|
||||
"publicClient": false,
|
||||
"frontchannelLogout": true,
|
||||
"protocol": "openid-connect",
|
||||
"attributes": {
|
||||
"oidc.ciba.grant.enabled": "true",
|
||||
"oauth2.device.authorization.grant.enabled": "true",
|
||||
"client.secret.creation.time": "1690966874",
|
||||
"backchannel.logout.session.required": "true",
|
||||
"backchannel.logout.revoke.offline.tokens": "false"
|
||||
},
|
||||
"authenticationFlowBindingOverrides": {},
|
||||
"fullScopeAllowed": true,
|
||||
"nodeReRegistrationTimeout": -1,
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "Client IP Address",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usersessionmodel-note-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.session.note": "clientAddress",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "clientAddress",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Client Host",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usersessionmodel-note-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.session.note": "clientHost",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "clientHost",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Client ID",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usersessionmodel-note-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.session.note": "client_id",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "client_id",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
}
|
||||
],
|
||||
"defaultClientScopes": [
|
||||
"web-origins",
|
||||
"acr",
|
||||
"profile",
|
||||
"roles",
|
||||
"email"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"address",
|
||||
"phone",
|
||||
"offline_access",
|
||||
"microprofile-jwt"
|
||||
],
|
||||
"access": {
|
||||
"view": true,
|
||||
"configure": true,
|
||||
"manage": true
|
||||
}
|
||||
}
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@ -31,3 +31,9 @@ build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
.gradle/
|
||||
gradle.properties
|
||||
gradlew
|
||||
gradlew.bat
|
||||
.DS_Store
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,2 +0,0 @@
|
||||
#Wed Jun 14 12:04:30 EEST 2023
|
||||
gradle.version=8.1.1
|
||||
Binary file not shown.
Binary file not shown.
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Binary file not shown.
18
.mvn/wrapper/maven-wrapper.properties
vendored
18
.mvn/wrapper/maven-wrapper.properties
vendored
@ -1,18 +0,0 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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
|
||||
#
|
||||
# https://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.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
|
||||
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Tenant User Management Micro-Service: tenant-user-management
|
||||
|
||||
## Introduction
|
||||
The tenant-user-management micro-service profiles with storing and providing everything about the tenant environment. It makes use of tools like Spring Boot 3, Keycloak, Microsoft Azure and AWS S3 to keep your data consistent and secure according to the latest standards.
|
||||
|
||||
### Key features in the Tenant User Management Service
|
||||
|
||||
* **Tenant Management:**
|
||||
This service gives you the option to do CRUD operations to manage your tenants.
|
||||
You can also select between different storage platforms to store your tenants.
|
||||
Some general configurations complements the settings options.
|
||||
|
||||
|
||||
* **User Administration:**
|
||||
Another feature is the handling of your users. You can manage the profiles, activate/deactivate them and give roles as you require.
|
||||
If you wish you can administrate the users for each tenant separately.
|
||||
Or just give a user the needed preferences.
|
||||
|
||||
|
||||
* **SMTP configuration:**
|
||||
Further you can adjust your SMTP settings and set properties as you aimed best for your company.
|
||||
111
build.gradle.kts
111
build.gradle.kts
@ -2,11 +2,18 @@ import org.springframework.boot.gradle.tasks.bundling.BootBuildImage
|
||||
|
||||
plugins {
|
||||
java
|
||||
id("org.springframework.boot") version "3.0.6"
|
||||
id("org.springframework.boot") version "3.1.5"
|
||||
id("io.spring.dependency-management") version "1.1.0"
|
||||
id("org.sonarqube") version "4.0.0.2929"
|
||||
// pmd
|
||||
id("io.freefair.lombok") version "8.4"
|
||||
pmd
|
||||
`maven-publish`
|
||||
checkstyle
|
||||
jacoco
|
||||
}
|
||||
|
||||
pmd {
|
||||
isConsoleOutput = true
|
||||
}
|
||||
|
||||
configurations {
|
||||
@ -14,14 +21,30 @@ configurations {
|
||||
extendsFrom(configurations.annotationProcessor.get())
|
||||
}
|
||||
}
|
||||
tasks.pmdMain{
|
||||
pmd.ruleSetFiles = files("${projectDir}/config/pmd/pmd.xml")
|
||||
}
|
||||
|
||||
//tasks.pmdMain{
|
||||
// pmd.ruleSetFiles = files("${projectDir}/config/pmd/pmd.xml")
|
||||
//}
|
||||
//
|
||||
//tasks.pmdTest {
|
||||
// pmd.ruleSetFiles = files("${projectDir}/config/pmd/test_pmd.xml")
|
||||
//}
|
||||
tasks.pmdTest {
|
||||
pmd.ruleSetFiles = files("${projectDir}/config/pmd/test_pmd.xml")
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>(name) {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url = uri("https://nexus.knecon.com/repository/red-platform-releases/")
|
||||
credentials {
|
||||
username = providers.gradleProperty("mavenUser").getOrNull()
|
||||
password = providers.gradleProperty("mavenPassword").getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -29,16 +52,20 @@ repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri("https://nexus.knecon.com/repository/gindev/");
|
||||
url = uri("https://nexus.knecon.com/repository/gindev/")
|
||||
credentials {
|
||||
username = providers.gradleProperty("mavenUser").getOrNull();
|
||||
password = providers.gradleProperty("mavenPassword").getOrNull();
|
||||
username = providers.gradleProperty("mavenUser").getOrNull()
|
||||
password = providers.gradleProperty("mavenPassword").getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks.named<BootBuildImage>("bootBuildImage") {
|
||||
|
||||
environment.put("BPE_DELIM_JAVA_TOOL_OPTIONS", " ")
|
||||
environment.put("BPE_APPEND_JAVA_TOOL_OPTIONS", "-Dfile.encoding=UTF-8")
|
||||
|
||||
imageName.set("nexus.knecon.com:5001/ff/${project.name}:${project.version}")
|
||||
if (project.hasProperty("buildbootDockerHostNetwork")) {
|
||||
network.set("host")
|
||||
@ -59,13 +86,30 @@ tasks.named<BootBuildImage>("bootBuildImage") {
|
||||
}
|
||||
|
||||
|
||||
configurations {
|
||||
all {
|
||||
exclude(group = "commons-logging", module = "commons-logging")
|
||||
exclude(group = "org.springframework.boot", module = "spring-boot-starter-log4j2")
|
||||
exclude(group = "com.iqser.red.commons", module = "logging-commons")
|
||||
}
|
||||
}
|
||||
|
||||
val persistenceServiceVersion = "2.589.1-RED10196.2"
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation("com.knecon.fforesight:keycloak-commons:0.9.0")
|
||||
implementation("com.knecon.fforesight:swagger-commons:0.5.0")
|
||||
implementation("com.iqser.red.service:persistence-service-internal-api-v1:${persistenceServiceVersion}")
|
||||
implementation("com.knecon.fforesight:database-tenant-commons:0.28.0-RED10196.0")
|
||||
implementation("com.knecon.fforesight:keycloak-commons:0.28.0")
|
||||
implementation("com.knecon.fforesight:swagger-commons:0.7.0")
|
||||
implementation("com.knecon.fforesight:tracing-commons:0.5.0")
|
||||
implementation("com.knecon.fforesight:lifecycle-commons:0.6.0")
|
||||
implementation("net.logstash.logback:logstash-logback-encoder:7.4")
|
||||
implementation("ch.qos.logback:logback-classic")
|
||||
implementation("org.postgresql:postgresql:42.5.4")
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
implementation("org.liquibase:liquibase-core:4.17.2")
|
||||
implementation("org.keycloak:keycloak-admin-client:21.0.1")
|
||||
implementation("com.google.guava:guava:33.0.0-jre")
|
||||
implementation("org.liquibase:liquibase-core:4.20.0")
|
||||
implementation("org.keycloak:keycloak-admin-client:23.0.6")
|
||||
implementation("org.springframework.boot:spring-boot-starter-amqp")
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
implementation("org.springframework.retry:spring-retry")
|
||||
@ -74,28 +118,30 @@ dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
|
||||
implementation("org.apache.commons:commons-lang3:3.12.0")
|
||||
implementation("commons-validator:commons-validator:1.7")
|
||||
implementation("commons-validator:commons-validator:1.8.0")
|
||||
implementation("org.springframework.boot:spring-boot-configuration-processor")
|
||||
implementation("com.iqser.red.commons:storage-commons:2.45.0")
|
||||
implementation("jakarta.mail:jakarta.mail-api:2.1.2")
|
||||
implementation("org.eclipse.angus:angus-mail:2.0.2")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
|
||||
compileOnly("org.projectlombok:lombok")
|
||||
testImplementation("org.springframework.cloud:spring-cloud-starter-openfeign")
|
||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
||||
annotationProcessor("org.projectlombok:lombok")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||
testImplementation("org.springframework.amqp:spring-rabbit-test")
|
||||
testImplementation("org.testcontainers:elasticsearch:1.17.6")
|
||||
testAnnotationProcessor("org.projectlombok:lombok")
|
||||
|
||||
testImplementation("org.testcontainers:postgresql:1.19.7")
|
||||
testImplementation("org.testcontainers:testcontainers:1.19.7")
|
||||
testImplementation("org.testcontainers:junit-jupiter:1.19.7")
|
||||
testImplementation("com.github.dasniko:testcontainers-keycloak:3.2.0")
|
||||
}
|
||||
|
||||
extra["springCloudVersion"] = "2022.0.2"
|
||||
extra["testcontainersVersion"] = "1.17.6"
|
||||
extra["springCloudVersion"] = "2022.0.4"
|
||||
extra["testcontainersVersion"] = "1.19.7"
|
||||
|
||||
|
||||
group = "com.knecon.fforesight"
|
||||
version = "1.0-SNAPSHOT"
|
||||
description = "tenant-user-management-service"
|
||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
@ -119,3 +165,14 @@ sonarqube {
|
||||
property("sonar.host.url", "https://sonarqube.knecon.com")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run
|
||||
}
|
||||
tasks.jacocoTestReport {
|
||||
dependsOn(tasks.test) // tests are required to run before generating the report
|
||||
reports {
|
||||
xml.required.set(true)
|
||||
csv.required.set(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom Rules"
|
||||
<ruleset name="Custom ruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>Knecon main pmd rules</description>
|
||||
<description>
|
||||
Knecon ruleset checks the code for bad stuff
|
||||
</description>
|
||||
|
||||
<rule ref="category/java/errorprone.xml">
|
||||
<exclude name="DataflowAnomalyAnalysis"/>
|
||||
<exclude name="MissingSerialVersionUID"/>
|
||||
<exclude name="AvoidLiteralsInIfCondition"/>
|
||||
<exclude name="AvoidDuplicateLiterals"/>
|
||||
<exclude name="NullAssignment"/>
|
||||
<exclude name="AssignmentInOperand"/>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
|
||||
@ -1,14 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="Custom Rules"
|
||||
<ruleset name="Custom ruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Knecon test ruleset checks the code for bad stuff
|
||||
</description>
|
||||
|
||||
<description>Knecon test pmd rules</description>
|
||||
|
||||
<rule ref="category/java/errorprone.xml">
|
||||
<exclude name="DataflowAnomalyAnalysis"/>
|
||||
<exclude name="MissingSerialVersionUID"/>
|
||||
<exclude name="AvoidLiteralsInIfCondition"/>
|
||||
<exclude name="AvoidDuplicateLiterals"/>
|
||||
<exclude name="NullAssignment"/>
|
||||
<exclude name="AssignmentInOperand"/>
|
||||
<exclude name="TestClassWithoutTestCases"/>
|
||||
<exclude name="BeanMembersShouldSerialize"/>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
|
||||
1
gradle.properties.kts
Normal file
1
gradle.properties.kts
Normal file
@ -0,0 +1 @@
|
||||
version = 1.0-SNAPSHOT
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
245
gradlew
vendored
245
gradlew
vendored
@ -1,245 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
92
gradlew.bat
vendored
92
gradlew.bat
vendored
@ -1,92 +0,0 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
316
mvnw
vendored
316
mvnw
vendored
@ -1,316 +0,0 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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
|
||||
#
|
||||
# https://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.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ] ; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ] ; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ] ; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ] ; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false;
|
||||
darwin=false;
|
||||
mingw=false
|
||||
case "`uname`" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true;;
|
||||
Darwin*) darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="`which javac`"
|
||||
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=`which readlink`
|
||||
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
|
||||
if $darwin ; then
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
|
||||
else
|
||||
javaExecutable="`readlink -f \"$javaExecutable\"`"
|
||||
fi
|
||||
javaHome="`dirname \"$javaExecutable\"`"
|
||||
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ] ; then
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="`\\unset -f command; \\command -v java`"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set."
|
||||
fi
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo "Path not specified to find_maven_basedir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ] ; do
|
||||
if [ -d "$wdir"/.mvn ] ; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=`cd "$wdir/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
fi
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
|
||||
[ -n "$CLASSPATH" ] &&
|
||||
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
|
||||
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
||||
188
mvnw.cmd
vendored
188
mvnw.cmd
vendored
@ -1,188 +0,0 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM https://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Maven Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo.
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo.
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
||||
191
pom.xml
191
pom.xml
@ -1,191 +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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.0.6</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.knecon.fforesight</groupId>
|
||||
<artifactId>tenant-user-management-service</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>tenant-user-management-service</name>
|
||||
<description>tenant-user-management-service</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<keycloak.version>21.0.1</keycloak.version>
|
||||
<commons-validator.version>1.7</commons-validator.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<swagger-commons.version>0.5.0</swagger-commons.version>
|
||||
<keycloak-commons.version>0.9.0</keycloak-commons.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.knecon.fforesight</groupId>
|
||||
<artifactId>keycloak-commons</artifactId>
|
||||
<version>${keycloak-commons.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.knecon.fforesight</groupId>
|
||||
<artifactId>swagger-commons</artifactId>
|
||||
<version>${swagger-commons.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.liquibase</groupId>
|
||||
<artifactId>liquibase-core</artifactId>
|
||||
<version>${liquibase.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-admin-client</artifactId>
|
||||
<version>${keycloak.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<version>${commons-validator.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>3.9.0.2155</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>6.3.1</version>
|
||||
<configuration>
|
||||
<format>ALL</format>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<goals>
|
||||
<goal>report-aggregate</goal>
|
||||
</goals>
|
||||
<phase>verify</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
8
publish-custom-image.sh
Executable file
8
publish-custom-image.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
dir=${PWD##*/}
|
||||
gradle assemble
|
||||
|
||||
buildNumber=${1:-1}
|
||||
|
||||
gradle bootBuildImage --cleanCache --publishImage -PbuildbootDockerHostNetwork=true -Pversion=$USER-$buildNumber
|
||||
echo "nexus.knecon.com:5001/ff/${dir}:$USER-$buildNumber"
|
||||
@ -1,163 +0,0 @@
|
||||
package com.knecon.fforesight.tenantusermanagement;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.knecon.fforesight.tenantcommons.model.DatabaseConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.S3StorageConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.SearchConnection;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Profile("dev")
|
||||
@Configuration
|
||||
public class DevConfiguration {
|
||||
|
||||
@Autowired
|
||||
private TenantManagementService tenantManagementService;
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@Value("${spring.datasource.url:}")
|
||||
private String masterJDBCURL;
|
||||
@Autowired
|
||||
private TenantUserManagementProperties tenantUserManagementProperties;
|
||||
|
||||
|
||||
@PostConstruct
|
||||
@SneakyThrows
|
||||
public void createDefaultTenant() {
|
||||
|
||||
log.info("Creating Redaction Tenant");
|
||||
// tenantRepository.deleteAll();
|
||||
|
||||
if (tenantManagementService.getTenants().isEmpty()) {
|
||||
|
||||
var jdbcUrl = masterJDBCURL.substring(0, masterJDBCURL.lastIndexOf('/') + 1) + "redaction?currentSchema=redaction";
|
||||
|
||||
createDatabase("redaction", "redaction");
|
||||
createSchema(jdbcUrl, "redaction", "redaction");
|
||||
|
||||
var tenantRequest = TenantRequest.builder()
|
||||
.tenantId("redaction")
|
||||
.displayName("Redaction default")
|
||||
.guid(UUID.randomUUID().toString())
|
||||
.databaseConnection(DatabaseConnection.builder()
|
||||
.driver("postgresql")
|
||||
.host("localhost")
|
||||
.port("5432")
|
||||
.database("redaction")
|
||||
.schema("redaction")
|
||||
.username("redaction")
|
||||
.password("redaction")
|
||||
.build())
|
||||
.searchConnection(SearchConnection.builder()
|
||||
.hosts(Set.of("localhost"))
|
||||
.port(9200)
|
||||
.scheme("http")
|
||||
.numberOfShards("1")
|
||||
.numberOfReplicas("5")
|
||||
.build())
|
||||
.s3StorageConnection(S3StorageConnection.builder().key("minioadmin").secret("minioadmin").bucketName("redaction").endpoint("http://localhost:9000").build())
|
||||
.build();
|
||||
|
||||
tenantManagementService.createTenant(tenantRequest);
|
||||
|
||||
}
|
||||
|
||||
TenantContext.setTenantId("redaction");
|
||||
}
|
||||
|
||||
|
||||
private void createDatabase(String db, String password) {
|
||||
|
||||
var jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE DATABASE " + db));
|
||||
} catch (Exception e) {
|
||||
log.warn("DB already exists");
|
||||
}
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE USER " + db + " WITH ENCRYPTED PASSWORD '" + password + "'"));
|
||||
} catch (Exception e) {
|
||||
log.warn("user already exists");
|
||||
}
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT ALL PRIVILEGES ON DATABASE " + db + " TO " + db));
|
||||
} catch (Exception e) {
|
||||
log.warn("grant invalid");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createSchema(String jdbcUrl, String username, String password) {
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
JdbcTemplate insert = new JdbcTemplate(tenantDataSource);
|
||||
try {
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA redaction"));
|
||||
} catch (Exception e) {
|
||||
log.warn("schema already exists");
|
||||
}
|
||||
try {
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA redaction TO " + username));
|
||||
} catch (Exception e) {
|
||||
log.warn("grant invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public byte[] pack(String sourceDirPath) throws IOException {
|
||||
|
||||
var bos = new ByteArrayOutputStream();
|
||||
var p = Paths.get(sourceDirPath);
|
||||
try (ZipOutputStream zs = new ZipOutputStream(bos)) {
|
||||
Stream<Path> paths = Files.walk(p);
|
||||
{
|
||||
paths.filter(path -> !Files.isDirectory(path)).forEach(path -> {
|
||||
ZipEntry zipEntry = new ZipEntry(p.relativize(path).toString());
|
||||
try {
|
||||
zs.putNextEntry(zipEntry);
|
||||
Files.copy(path, zs);
|
||||
zs.closeEntry();
|
||||
} catch (IOException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return bos.toByteArray();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,18 +4,26 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
import com.knecon.fforesight.keycloakcommons.DefaultKeyCloakCommonsAutoConfiguration;
|
||||
import com.knecon.fforesight.lifecyclecommons.LifecycleAutoconfiguration;
|
||||
import com.knecon.fforesight.swaggercommons.SpringDocAutoConfiguration;
|
||||
import com.knecon.fforesight.tenantcommons.MultiTenancyAutoConfiguration;
|
||||
import com.knecon.fforesight.tenantusermanagement.client.LicenseClient;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@ImportAutoConfiguration({ MultiTenancyAutoConfiguration.class, LiquibaseAutoConfiguration.class, DefaultKeyCloakCommonsAutoConfiguration.class, SpringDocAutoConfiguration.class})
|
||||
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, CassandraAutoConfiguration.class,})
|
||||
@ImportAutoConfiguration({MultiTenancyAutoConfiguration.class, LiquibaseAutoConfiguration.class, DefaultKeyCloakCommonsAutoConfiguration.class, SpringDocAutoConfiguration.class, LifecycleAutoconfiguration.class})
|
||||
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, CassandraAutoConfiguration.class, MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
|
||||
@EnableAspectJAutoProxy
|
||||
@EnableFeignClients(basePackageClasses = LicenseClient.class)
|
||||
public class TenantUserManagementServiceApplication {
|
||||
|
||||
/**
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
public interface TenantsResource {
|
||||
|
||||
String TENANT_ID_PARAM = "tenantId";
|
||||
String TENANT_ID_PATH_PARAM = "/{" + TENANT_ID_PARAM + "}";
|
||||
|
||||
|
||||
@PostMapping(value = "/tenants", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Creates a new Tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void createTenant(@RequestBody TenantRequest tenant);
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<TenantResponse> getTenants();
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants/{tenantId}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
TenantResponse getTenant(@PathVariable("tenantId") String tenantId);
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants/simple", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant in a simplified format", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<SimpleTenantResponse> getSimpleTenants();
|
||||
|
||||
|
||||
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId);
|
||||
|
||||
}
|
||||
@ -1,11 +1,10 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api;
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ -15,8 +14,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
|
||||
public interface GeneralSettingsResource {
|
||||
|
||||
String API_PATH = "/configuration/general";
|
||||
@ -25,15 +22,15 @@ public interface GeneralSettingsResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = API_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the current general Configuration.")
|
||||
@Operation(summary = "Returns the current general configuration")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK.")})
|
||||
GeneralConfigurationModel getGeneralConfigurations();
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = API_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Write General Configurations to KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "General Configuration updated successful."), @ApiResponse(responseCode = "400", description = "General Configuration update failed.")})
|
||||
@Operation(summary = "Write general configuration to KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "General configuration updated successful."), @ApiResponse(responseCode = "400", description = "General configuration update failed.")})
|
||||
void updateGeneralConfigurations(@RequestBody GeneralConfigurationModel generalConfigurationModel);
|
||||
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderList;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderModel;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderWithDescriptorRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@Tag(name = "Identity provider configuration endpoints", description = "Provides operations related to the identity providers")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests."), @ApiResponse(responseCode = "403", description = "Forbidden")})
|
||||
public interface IdentityProviderConfigurationResource {
|
||||
|
||||
String API_PATH = "/configuration/identity-providers";
|
||||
String IDENTITY_PROVIDER_ALIAS_PARAM = "providerAlias";
|
||||
String IDENTITY_PROVIDER_ALIAS_PATH_PARAM = "/{" + IDENTITY_PROVIDER_ALIAS_PARAM + "}";
|
||||
String IMPORT_SUB_PATH = "/import";
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@GetMapping(value = API_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing identity providers.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
IdentityProviderList getIdentityProviders();
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@GetMapping(value = API_PATH + IDENTITY_PROVIDER_ALIAS_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets an existing identity provider.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
IdentityProviderModel getIdentityProvider(@Parameter(name = IDENTITY_PROVIDER_ALIAS_PARAM, description = "The alias of the identity provider to retrieve.", required = true) @PathVariable(IDENTITY_PROVIDER_ALIAS_PARAM) String identityProviderAlias);
|
||||
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.CREATED)
|
||||
@ResponseBody
|
||||
@PostMapping(value = API_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Creates a new identity provider", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully created the identity provider"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body"), @ApiResponse(responseCode = "409", description = "Duplicate")})
|
||||
ResponseEntity<IdentityProviderModel> createIdentityProvider(@Valid @io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderRequest identityProvider);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.CREATED)
|
||||
@ResponseBody
|
||||
@PostMapping(value = API_PATH + IMPORT_SUB_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Creates a new identity provider", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully created the identity provider"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body"), @ApiResponse(responseCode = "409", description = "Duplicate")})
|
||||
ResponseEntity<IdentityProviderModel> createIdentityProviderFromDescriptor(@Valid @io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderWithDescriptorRequest identityProvider);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ResponseBody
|
||||
@PutMapping(value = API_PATH + IDENTITY_PROVIDER_ALIAS_PATH_PARAM, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Updates an existing identity provider", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully updated the identity provider"), @ApiResponse(responseCode = "404", description = "Not found"), @ApiResponse(responseCode = "400", description = "Malformed request parameters or body")})
|
||||
ResponseEntity<IdentityProviderModel> updateIdentityProvider(@Parameter(name = IDENTITY_PROVIDER_ALIAS_PARAM, description = "The alias of the identity provider to retrieve.", required = true) @PathVariable(IDENTITY_PROVIDER_ALIAS_PARAM) String identityProviderAlias,
|
||||
@Valid @io.swagger.v3.oas.annotations.parameters.RequestBody @RequestBody IdentityProviderRequest identityProvider);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@DeleteMapping(value = API_PATH + IDENTITY_PROVIDER_ALIAS_PATH_PARAM)
|
||||
@Operation(summary = "Deletes an existing identity provider.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the identity provider."), @ApiResponse(responseCode = "404", description = "Not found")})
|
||||
void deleteIdentityProvider(@Parameter(name = IDENTITY_PROVIDER_ALIAS_PARAM, description = "The alias of the identity provider to retrieve.", required = true) @PathVariable(IDENTITY_PROVIDER_ALIAS_PARAM) String identityProviderAlias);
|
||||
|
||||
}
|
||||
8
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/PublicResource.java
vendored
Normal file
8
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/PublicResource.java
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
public interface PublicResource {
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api;
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -6,29 +6,27 @@ import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPResponse;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
|
||||
public interface SMTPConfigurationResource {
|
||||
|
||||
String SMTP_PATH = "/configuration/smtp";
|
||||
|
||||
String TEST_PATH = "/test";
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = SMTP_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the current SMTP Configuration.")
|
||||
@Operation(summary = "Returns the current SMTP configuration.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK."), @ApiResponse(responseCode = "404", description = "SMTP not configured.")})
|
||||
SMTPConfiguration getCurrentSMTPConfiguration();
|
||||
|
||||
@ -36,21 +34,22 @@ public interface SMTPConfigurationResource {
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@PostMapping(value = SMTP_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Write SMTP Settings to KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "SMTP Configuration updated successful."), @ApiResponse(responseCode = "400", description = "SMTP update failed.")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "SMTP configuration updated successful."), @ApiResponse(responseCode = "400", description = "SMTP update failed.")})
|
||||
void updateSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = SMTP_PATH + TEST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@PostMapping(value = SMTP_PATH + TEST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Test SMTP Settings to KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "SMTP Configuration is valid."), @ApiResponse(responseCode = "400", description = "SMTP test failed.")})
|
||||
void testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "SMTP configuration is valid."), @ApiResponse(responseCode = "400", description = "SMTP test failed.")})
|
||||
SMTPResponse testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@DeleteMapping(value = SMTP_PATH)
|
||||
@Operation(summary = "Clear SMTP Settings to KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "SMTP Configuration has been cleared."), @ApiResponse(responseCode = "400", description = "Failed to clear SMTP Configuration.")})
|
||||
@Operation(summary = "Deletes SMTP settings on KeyCloak")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "SMTP configuration has been deleted."), @ApiResponse(responseCode = "400", description = "Failed to delete SMTP configuration.")})
|
||||
void clearSMTPConfiguration();
|
||||
|
||||
}
|
||||
85
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/TenantsResource.java
vendored
Normal file
85
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/TenantsResource.java
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public interface TenantsResource {
|
||||
|
||||
String TENANTS_PATH = "/tenants";
|
||||
String TENANT_ID_PARAM = "tenantId";
|
||||
String TENANT_ID_PATH_PARAM = "/{" + TENANT_ID_PARAM + "}";
|
||||
String TENANTS_TENANT_ID_PATH = TENANTS_PATH + TENANT_ID_PATH_PARAM;
|
||||
|
||||
|
||||
@PostMapping(value = TENANTS_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Create a new tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void createTenant(@RequestBody CreateTenantRequest tenant);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Deletes given tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden access, you dont have rights to delete tenants"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."), @ApiResponse(responseCode = "409", description = "Conflict while deleting tenant.")})
|
||||
@DeleteMapping(value = TENANTS_TENANT_ID_PATH)
|
||||
void deleteTenant(@PathVariable("tenantId") String tenantId);
|
||||
|
||||
|
||||
@GetMapping(value = TENANTS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenants", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<TenantResponse> getTenants();
|
||||
|
||||
|
||||
@GetMapping(value = TENANTS_TENANT_ID_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets an existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
TenantResponse getTenant(@PathVariable("tenantId") String tenantId);
|
||||
|
||||
|
||||
@PutMapping(value = TENANTS_TENANT_ID_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest);
|
||||
|
||||
|
||||
@PostMapping(value = TENANTS_TENANT_ID_PATH + "/details", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update details", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request);
|
||||
|
||||
|
||||
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the deployment key for a tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId);
|
||||
|
||||
|
||||
@PostMapping(value = TENANTS_TENANT_ID_PATH + "/sync", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Sync existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void syncTenant(@PathVariable("tenantId") String tenantId, @RequestBody JsonNode payload);
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api;
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -18,8 +18,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
|
||||
public interface UserPreferenceResource {
|
||||
|
||||
String PREFERENCES_PATH = "/attributes";
|
||||
@ -30,14 +28,14 @@ public interface UserPreferenceResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = PREFERENCES_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Get User Attributes.", description = "None")
|
||||
@Operation(summary = "Gets user attributes", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
Map<String, List<String>> getAllUserAttributes();
|
||||
|
||||
|
||||
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||
@PutMapping(value = PREFERENCES_PATH + KEY_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Store User Attribute by key.", description = "None")
|
||||
@Operation(summary = "Store user attribute by key", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
void setAttribute(@PathVariable(KEY_PARAMETER_NAME) String key, @RequestBody List<String> values);
|
||||
|
||||
@ -45,7 +43,7 @@ public interface UserPreferenceResource {
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@DeleteMapping(value = PREFERENCES_PATH + KEY_PATH_VARIABLE)
|
||||
@Operation(summary = "Delete User Preferences by key.", description = "None")
|
||||
@Operation(summary = "Delete user preferences by key", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
|
||||
void deleteAttribute(@PathVariable(KEY_PARAMETER_NAME) String key);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api;
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
@ -26,8 +25,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}")
|
||||
|
||||
public interface UserResource {
|
||||
|
||||
String USER_REST_PATH = "/user";
|
||||
@ -47,33 +44,33 @@ public interface UserResource {
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Gets the users who contain application-specific roles.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid " + "offset or limit specified.")})
|
||||
@Operation(summary = "Gets the users holding application-specific roles", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid offset or limit specified.")})
|
||||
@GetMapping(value = RED_USER_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<User> getApplicationSpecificUsers(@RequestParam(name = REFRESH_CACHE_PARAM, defaultValue = "false", required = false) boolean bypassCache);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Gets all the users in realm with information of roles.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid " + "offset or limit specified.")})
|
||||
@Operation(summary = "Gets all users in realm including role info", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid offset or limit specified.")})
|
||||
@GetMapping(value = USER_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<User> getAllUsers(@RequestParam(name = REFRESH_CACHE_PARAM, defaultValue = "false", required = false) boolean bypassCache);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Update your own user-profile.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to update profile, e-mail cannot be empty")})
|
||||
@PostMapping(value = UPDATE_USER_PROFILE_PATH + USER_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void updateProfile(@PathVariable(USER_ID) String userId, @RequestBody UpdateProfileRequest updateProfileRequest);
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Update a user profile", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to update profile, e-mail invalid"), @ApiResponse(responseCode = "404", description = "The userId cannot be found.")})
|
||||
@PostMapping(value = UPDATE_USER_PROFILE_PATH + USER_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User updateProfile(@PathVariable(USER_ID) String userId, @RequestBody UpdateProfileRequest updateProfileRequest);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Update your own user-profile.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to update profile, e-mail cannot be empty")})
|
||||
@PostMapping(value = UPDATE_MY_USER_PROFILE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void updateMyProfile(@RequestBody UpdateMyProfileRequest updateProfileRequest);
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Update your user profile", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to update profile, e-mail invalid")})
|
||||
@PostMapping(value = UPDATE_MY_USER_PROFILE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User updateMyProfile(@RequestBody UpdateMyProfileRequest updateProfileRequest);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ -93,36 +90,36 @@ public interface UserResource {
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Create a new user.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid Data."), @ApiResponse(responseCode = "409", description = "User already exists.")})
|
||||
@Operation(summary = "Create a new user", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid Data.")})
|
||||
@PostMapping(value = USER_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User createUser(@RequestBody CreateUserRequest user);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Gets the user in realm with information of roles.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The " + "userId can not be found."), @ApiResponse(responseCode = "400", description = "The provided user id is empty or " + "null.")})
|
||||
@Operation(summary = "Gets the user in realm including role info", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The userId cannot be found."), @ApiResponse(responseCode = "400", description = "The provided user id is empty or null.")})
|
||||
@GetMapping(value = USER_REST_PATH + USER_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User getUserById(@PathVariable(USER_ID) String userId);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Add a role to users", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content"), @ApiResponse(responseCode = "404", description = "The provided userId can not be found."), @ApiResponse(responseCode = "400", description = "One ore more roles are not valid.")})
|
||||
@PostMapping(value = USER_ROLE_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void setRoles(@PathVariable(USER_ID) String userId, @RequestBody Set<String> roles);
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@Operation(summary = "Add roles to a user", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content"), @ApiResponse(responseCode = "404", description = "The provided userId cannot be found."), @ApiResponse(responseCode = "400", description = "One ore more roles are not valid.")})
|
||||
@PostMapping(value = USER_ROLE_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User setRoles(@PathVariable(USER_ID) String userId, @RequestBody Set<String> roles);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@Operation(summary = "Reset a user's password", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content"), @ApiResponse(responseCode = "404", description = "The provided userId can not be found.")})
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "No Content"), @ApiResponse(responseCode = "404", description = "The provided userId cannot be found.")})
|
||||
@PostMapping(value = RESET_PASSWORD_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
void resetPassword(@PathVariable(USER_ID) String userId, @RequestBody ResetPasswordRequest resetPasswordRequest);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Activate/ deactivate a user-profile.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to activate/deactivate profile")})
|
||||
@Operation(summary = "Activate/deactivate a user profile", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Failed to activate/deactivate profile"), @ApiResponse(responseCode = "403", description = "Cannot activate/deactivate users with higher rank roles"), @ApiResponse(responseCode = "404", description = "The userId cannot be found.")})
|
||||
@PostMapping(value = ACTIVATE_USER_PROFILE_PATH + USER_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User activateProfile(@PathVariable(USER_ID) String userId, @RequestParam(IS_ACTIVE_PARAM) boolean isActive);
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external.v2;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path-v2:/api}")
|
||||
public interface PublicResourceV2 {
|
||||
|
||||
}
|
||||
38
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/UserResourceV2.java
vendored
Normal file
38
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/UserResourceV2.java
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external.v2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.v2.model.User;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
public interface UserResourceV2 {
|
||||
|
||||
String USER_REST_PATH = "/users";
|
||||
String USER_ID = "userId";
|
||||
String USER_ID_PATH_VARIABLE = "/{" + USER_ID + "}";
|
||||
String USERNAME_PARAM = "username";
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Get a list of users", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Invalid offset or limit specified.")})
|
||||
@GetMapping(value = USER_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
List<User> getUsers(@RequestParam(name = USERNAME_PARAM, required = false) String username);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@Operation(summary = "Retrieve a specific user by its identifier.", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The " + "userId cannot be found."), @ApiResponse(responseCode = "400", description = "The provided user id is empty or " + "null.")})
|
||||
@GetMapping(value = USER_REST_PATH + USER_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
User getUserById(@PathVariable(USER_ID) String userId);
|
||||
|
||||
}
|
||||
29
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/model/User.java
vendored
Normal file
29
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/model/User.java
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external.v2.model;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class User {
|
||||
|
||||
private String id;
|
||||
private String username;
|
||||
private String email;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private boolean active;
|
||||
|
||||
@Builder.Default
|
||||
private Set<String> roles = new TreeSet<>();
|
||||
|
||||
}
|
||||
18
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/model/UserList.java
vendored
Normal file
18
src/main/java/com/knecon/fforesight/tenantusermanagement/api/external/v2/model/UserList.java
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.external.v2.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserList {
|
||||
|
||||
private List<User> users = new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.api.internal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RequestMapping("/internal")
|
||||
public interface InternalResource {
|
||||
|
||||
}
|
||||
@ -7,49 +7,57 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.knecon.fforesight.tenantcommons.TenantApplicationType;
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}/internal")
|
||||
public interface InternalTenantsResource {
|
||||
|
||||
String TENANT_ID_PARAM = "tenantId";
|
||||
String TENANT_ID_PATH_PARAM = "/{" + TENANT_ID_PARAM + "}";
|
||||
|
||||
|
||||
@PostMapping(value = "/tenants/{tenantId}/details", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update details", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request);
|
||||
|
||||
|
||||
@PostMapping(value = "/tenants", consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Creates a new Tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void createTenant(@RequestBody TenantRequest tenant);
|
||||
TenantResponse createTenant(@RequestBody CreateTenantRequest tenant);
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant", description = "None")
|
||||
@Operation(summary = "Gets all existing tenants", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<TenantResponse> getTenants();
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants/{tenantId}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant", description = "None")
|
||||
@Operation(summary = "Get the given tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
TenantResponse getTenant(@PathVariable("tenantId") String tenantId);
|
||||
|
||||
|
||||
@GetMapping(value = "/tenants/simple", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets all existing tenant in a simplified format", description = "None")
|
||||
@PutMapping(value = "/tenants/{tenantId}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Update existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<SimpleTenantResponse> getSimpleTenants();
|
||||
TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest);
|
||||
|
||||
|
||||
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ -57,4 +65,16 @@ public interface InternalTenantsResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId);
|
||||
|
||||
|
||||
@PostMapping(value = "/tenants/{tenantId}/sync", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Sync existing tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
void syncTenant(@PathVariable("tenantId") String tenantId, @RequestBody JsonNode payload);
|
||||
|
||||
|
||||
@GetMapping(value = {"/tenants/{tenantId}/application-type"}, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the application type of the given tenant", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
TenantApplicationType getTenantApplicationType(@PathVariable("tenantId") String tenantId);
|
||||
|
||||
}
|
||||
|
||||
@ -17,7 +17,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@RequestMapping("${fforesight.tenant-user-management.base-path:}/internal")
|
||||
public interface InternalUserResource {
|
||||
|
||||
String USER_REST_PATH = "/user";
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.internal.resources.LicenseResource;
|
||||
|
||||
@FeignClient(name = "LicenseResource", url = "${persistence-service.url}")
|
||||
public interface LicenseClient extends LicenseResource {
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import com.iqser.red.storage.commons.service.azure.AzureBlobStorageService;
|
||||
import com.iqser.red.storage.commons.service.s3.S3StorageService;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Configuration
|
||||
@Getter
|
||||
@ComponentScan("com.iqser.red.storage.commons")
|
||||
public class StorageConfiguration {
|
||||
|
||||
S3StorageService s3StorageService;
|
||||
|
||||
AzureBlobStorageService azureBlobStorageService;
|
||||
|
||||
@Autowired
|
||||
public void setS3StorageService(@Lazy S3StorageService s3StorageService) {
|
||||
this.s3StorageService = s3StorageService;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setAzureBlobStorageService(@Lazy AzureBlobStorageService azureBlobStorageService) {
|
||||
this.azureBlobStorageService = azureBlobStorageService;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
|
||||
import com.knecon.fforesight.tenantusermanagement.exception.ConflictException;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.ErrorMessage;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class ControllerAdvice {
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ErrorMessage> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
|
||||
var errorList = e.getFieldErrors();
|
||||
String errorListAsString = errorList.stream().map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()).collect(Collectors.joining(", "));
|
||||
return new ResponseEntity<>(new ErrorMessage(String.format("You have empty/wrong formatted parameters: %s", errorListAsString)), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(NotFoundException.class)
|
||||
public ResponseEntity<ErrorMessage> handleNotFound(NotFoundException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(ForbiddenException.class)
|
||||
public ResponseEntity<ErrorMessage> handleForbiddenAccess(ForbiddenException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(ResponseStatusException.class)
|
||||
public ResponseEntity<ErrorMessage> handleResponseStatusException(ResponseStatusException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getReason()), e.getStatusCode());
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(BadRequestException.class)
|
||||
public ResponseEntity<ErrorMessage> handleBadRequestException(BadRequestException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseEntity<ErrorMessage> handleAccessDeniedException(AccessDeniedException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(ConflictException.class)
|
||||
public ResponseEntity<ErrorMessage> handleConflictException(ConflictException e) {
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(e.getMessage()), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
@ExceptionHandler({HttpMessageNotReadableException.class})
|
||||
public ResponseEntity<ErrorMessage> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
|
||||
|
||||
String errorMessage = e.getMessage();
|
||||
var cause = e.getCause();
|
||||
if (cause instanceof InvalidFormatException invalidFormatException) {
|
||||
|
||||
errorMessage = cause.getMessage();
|
||||
Class<?> targetType = invalidFormatException.getTargetType();
|
||||
if (targetType != null && targetType.isEnum()) {
|
||||
errorMessage = String.format("Unsupported value for %s", targetType.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
return new ResponseEntity<>(new ErrorMessage(errorMessage), HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_SMTP_CONFIGURATION;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.WRITE_SMTP_CONFIGURATION;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.SMTPConfigurationResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class SMTPConfigurationController implements SMTPConfigurationResource {
|
||||
|
||||
private final static String DEFAULT_PASSWORD = "********";
|
||||
private final static String SMTP_PASSWORD_KEY = "FFORESIGHT_SMTP_PASSWORD";
|
||||
private final RealmService realmService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final EncryptionDecryptionService encryptionDecryptionService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_SMTP_CONFIGURATION + "')")
|
||||
public SMTPConfiguration getCurrentSMTPConfiguration() {
|
||||
|
||||
var realm = realmService.realm(TenantContext.getTenantId()).toRepresentation();
|
||||
return objectMapper.convertValue(realm.getSmtpServer(), SMTPConfiguration.class);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public void updateSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) {
|
||||
|
||||
var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation();
|
||||
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
|
||||
realmRepresentation.setSmtpServer(propertiesMap);
|
||||
|
||||
if (!smtpConfigurationModel.getPassword().equalsIgnoreCase(DEFAULT_PASSWORD)) {
|
||||
realmRepresentation.getAttributesOrEmpty().put(SMTP_PASSWORD_KEY, encryptionDecryptionService.encrypt(smtpConfigurationModel.getPassword()));
|
||||
}
|
||||
|
||||
realmService.realm(TenantContext.getTenantId()).update(realmRepresentation);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> convertSMTPConfigurationModelToMap(SMTPConfiguration smtpConfigurationModel) {
|
||||
|
||||
Map<String, Object> propertiesMap = objectMapper.convertValue(smtpConfigurationModel, Map.class);
|
||||
Map<String, String> stringPropertiesMap = new HashMap<>();
|
||||
propertiesMap.forEach((key, value) -> {
|
||||
if (value != null) {
|
||||
stringPropertiesMap.put(key, value.toString());
|
||||
} else {
|
||||
stringPropertiesMap.put(key, "");
|
||||
}
|
||||
});
|
||||
return stringPropertiesMap;
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public void testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) {
|
||||
|
||||
var propertiesMap = convertSMTPConfigurationModelToMap(smtpConfigurationModel);
|
||||
realmService.realm(TenantContext.getTenantId()).testSMTPConnection(propertiesMap);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public void clearSMTPConfiguration() {
|
||||
// also update in KC
|
||||
var realmRepresentation = realmService.realm(TenantContext.getTenantId()).toRepresentation();
|
||||
realmRepresentation.setSmtpServer(new HashMap<>());
|
||||
realmRepresentation.getAttributesOrEmpty().remove(SMTP_PASSWORD_KEY);
|
||||
realmService.realm(TenantContext.getTenantId()).update(realmRepresentation);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,72 +0,0 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.CREATE_TENANT;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.DEPLOYMENT_INFO;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.GET_TENANTS;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.TenantsResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class TenantsController implements TenantsResource {
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
private final DeploymentKeyService deploymentKeyService;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + CREATE_TENANT + "')")
|
||||
public void createTenant(@Valid @RequestBody TenantRequest tenantRequest) {
|
||||
|
||||
try {
|
||||
tenantManagementService.createTenant(tenantRequest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_TENANTS + "')")
|
||||
public List<TenantResponse> getTenants() {
|
||||
|
||||
return tenantManagementService.getTenants();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_TENANTS + "')")
|
||||
public TenantResponse getTenant(String tenantId) {
|
||||
|
||||
return tenantManagementService.getTenant(tenantId);
|
||||
}
|
||||
|
||||
|
||||
public List<SimpleTenantResponse> getSimpleTenants() {
|
||||
|
||||
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DEPLOYMENT_INFO + "')")
|
||||
public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
||||
|
||||
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_GENERAL_CONFIGURATION;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.WRITE_GENERAL_CONFIGURATION;
|
||||
@ -7,9 +7,12 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.api.GeneralSettingsResource;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.GeneralSettingsResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.GeneralConfigurationModel;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.GeneralConfigurationService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -17,16 +20,17 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class GeneralSettingsController implements GeneralSettingsResource {
|
||||
public class GeneralSettingsController implements GeneralSettingsResource, PublicResource {
|
||||
|
||||
private final GeneralConfigurationService generalConfigurationService;
|
||||
private final TenantManagementService tenantManagementService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_GENERAL_CONFIGURATION + "')")
|
||||
public GeneralConfigurationModel getGeneralConfigurations() {
|
||||
|
||||
return generalConfigurationService.getGeneralConfigurations();
|
||||
return generalConfigurationService.getGeneralConfigurations(tenantManagementService.getTenantApplicationType(TenantContext.getTenantId()));
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +38,7 @@ public class GeneralSettingsController implements GeneralSettingsResource {
|
||||
@PreAuthorize("hasAuthority('" + WRITE_GENERAL_CONFIGURATION + "')")
|
||||
public void updateGeneralConfigurations(@RequestBody GeneralConfigurationModel generalConfigurationModel) {
|
||||
|
||||
generalConfigurationService.updateGeneralConfigurations(generalConfigurationModel);
|
||||
generalConfigurationService.updateGeneralConfigurations(generalConfigurationModel, tenantManagementService.getTenantApplicationType(TenantContext.getTenantId()));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,269 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_IDENTITY_PROVIDER_CONFIGURATION;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.WRITE_IDENTITY_PROVIDER_CONFIGURATION;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.IdentityProviderConfigurationResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.exception.ConflictException;
|
||||
import com.knecon.fforesight.tenantusermanagement.exception.IdentityProviderExistsAlreadyException;
|
||||
import com.knecon.fforesight.tenantusermanagement.exception.IdentityProviderNotFoundException;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderList;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderModel;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.IdentityProviderWithDescriptorRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.KeyCloakAdminClientService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
||||
import com.knecon.fforesight.tenantusermanagement.utils.IdentityProviderMappingService;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.InternalServerErrorException;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class IdentityProviderConfigurationController implements IdentityProviderConfigurationResource, PublicResource {
|
||||
|
||||
private final RealmService realmService;
|
||||
private final TenantUserManagementProperties tenantUserManagementProperties;
|
||||
private final KeyCloakAdminClientService keyCloakAdminClientService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public IdentityProviderList getIdentityProviders() {
|
||||
|
||||
return new IdentityProviderList(getRealmRepresentation().getIdentityProviders()
|
||||
.stream()
|
||||
.map(IdentityProviderMappingService::toModelFromRepresentation)
|
||||
.toList());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public IdentityProviderModel getIdentityProvider(String identityProviderAlias) {
|
||||
|
||||
return IdentityProviderMappingService.toModelFromRepresentation(getIdentityProviderRepresentation(identityProviderAlias));
|
||||
}
|
||||
|
||||
|
||||
private IdentityProviderRepresentation getIdentityProviderRepresentation(String identityProviderAlias) {
|
||||
|
||||
return getRealmRepresentation().getIdentityProviders()
|
||||
.stream()
|
||||
.filter(identityProviderRepresentation -> identityProviderRepresentation.getAlias().equals(identityProviderAlias))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IdentityProviderNotFoundException(identityProviderAlias));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public ResponseEntity<IdentityProviderModel> createIdentityProvider(IdentityProviderRequest identityProviderRequest) {
|
||||
|
||||
if (identityProviderRequest.getAlias() == null) {
|
||||
throw new BadRequestException("Alias must not be null.");
|
||||
}
|
||||
|
||||
if (identityProviderRequest.getDisplayName() == null || identityProviderRequest.getDisplayName().isEmpty()) {
|
||||
identityProviderRequest.setDisplayName(identityProviderRequest.getAlias());
|
||||
}
|
||||
checkIfOtherIdpHasSameDisplayNameOnCreate(identityProviderRequest.getDisplayName());
|
||||
|
||||
IdentityProviderModel identityProviderModel = IdentityProviderMappingService.toModelFromRequest(identityProviderRequest);
|
||||
return callKeyCloakIdentityProvidersCreateForModel(identityProviderModel);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public ResponseEntity<IdentityProviderModel> createIdentityProviderFromDescriptor(IdentityProviderWithDescriptorRequest identityProviderWithDescriptorRequest) {
|
||||
|
||||
if (identityProviderWithDescriptorRequest.getDisplayName() == null || identityProviderWithDescriptorRequest.getDisplayName().isEmpty()) {
|
||||
identityProviderWithDescriptorRequest.setDisplayName(identityProviderWithDescriptorRequest.getAlias());
|
||||
}
|
||||
checkIfOtherIdpHasSameDisplayNameOnCreate(identityProviderWithDescriptorRequest.getDisplayName());
|
||||
|
||||
Map<String, Object> requestMap = new HashMap<>();
|
||||
requestMap.put("providerId", identityProviderWithDescriptorRequest.getProviderId());
|
||||
requestMap.put("fromUrl", identityProviderWithDescriptorRequest.getSamlEntityDescriptorURL());
|
||||
|
||||
try {
|
||||
Map<String, String> configurationsMap = realmService.realm(getTenantId()).identityProviders().importFrom(requestMap);
|
||||
|
||||
if (configurationsMap == null || configurationsMap.isEmpty()) {
|
||||
throw new BadRequestException("Could not set config from provided descriptor.");
|
||||
}
|
||||
|
||||
configurationsMap.put("entityId", identityProviderWithDescriptorRequest.getEntityId());
|
||||
IdentityProviderModel identityProviderModel = IdentityProviderMappingService.toModelFromDescriptorRequestAndConfig(identityProviderWithDescriptorRequest,
|
||||
configurationsMap);
|
||||
return callKeyCloakIdentityProvidersCreateForModel(identityProviderModel);
|
||||
|
||||
} catch (InternalServerErrorException internalServerErrorException) {
|
||||
throw new BadRequestException("Provided descriptor is malformed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ResponseEntity<IdentityProviderModel> callKeyCloakIdentityProvidersCreateForModel(IdentityProviderModel identityProviderModel) {
|
||||
|
||||
identityProviderModel.setSpecificDefaults();
|
||||
|
||||
try (Response response = realmService.realm(getTenantId()).identityProviders().create(IdentityProviderMappingService.toRepresentationFromModel(identityProviderModel))) {
|
||||
var httpStatus = HttpStatus.valueOf(response.getStatus());
|
||||
switch (httpStatus) {
|
||||
case CREATED -> {
|
||||
IdentityProviderModel createdIdentityProvider = getIdentityProvider(identityProviderModel.getAlias());
|
||||
return new ResponseEntity<>(createdIdentityProvider, HttpStatus.valueOf(response.getStatus()));
|
||||
}
|
||||
case CONFLICT -> throw new IdentityProviderExistsAlreadyException(identityProviderModel.getAlias());
|
||||
default -> throw new ResponseStatusException(httpStatus, extractKeycloakErrorMessageInfos(response.readEntity(String.class)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public ResponseEntity<IdentityProviderModel> updateIdentityProvider(String identityProviderAlias, IdentityProviderRequest identityProviderRequest) {
|
||||
|
||||
identityProviderRequest.setAlias(identityProviderAlias);
|
||||
getIdentityProviderRepresentation(identityProviderAlias);
|
||||
|
||||
checkIfOtherIdpHasSameDisplayNameOnUpdate(identityProviderAlias, identityProviderRequest.getDisplayName());
|
||||
|
||||
IdentityProviderModel identityProviderModel = IdentityProviderMappingService.toModelFromRequest(identityProviderRequest);
|
||||
identityProviderModel.setSpecificDefaults();
|
||||
|
||||
var restTemplate = new RestTemplate();
|
||||
var url = getKeycloakIdentityProviderInstancesUrl() + identityProviderRequest.getAlias();
|
||||
var headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.add("Authorization", "Bearer " + getToken());
|
||||
HttpEntity<IdentityProviderModel> httpEntity = new HttpEntity<>(identityProviderModel, headers);
|
||||
try {
|
||||
ResponseEntity<?> response = restTemplate.exchange(url, HttpMethod.PUT, httpEntity, String.class);
|
||||
var httpStatus = HttpStatus.valueOf(response.getStatusCode().value());
|
||||
if (httpStatus == HttpStatus.NO_CONTENT) {
|
||||
IdentityProviderModel createdIdentityProvider = getIdentityProvider(identityProviderRequest.getAlias());
|
||||
return new ResponseEntity<>(createdIdentityProvider, HttpStatus.OK);
|
||||
} else if (httpStatus.is4xxClientError()) {
|
||||
throw new ResponseStatusException(httpStatus, "Bad request to keycloak API");
|
||||
} else {
|
||||
throw new ResponseStatusException(httpStatus, httpStatus.getReasonPhrase());
|
||||
}
|
||||
} catch (HttpClientErrorException e) {
|
||||
throw new ResponseStatusException(e.getStatusCode(), extractKeycloakErrorMessageInfos(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_IDENTITY_PROVIDER_CONFIGURATION + "')")
|
||||
public void deleteIdentityProvider(String identityProviderAlias) {
|
||||
|
||||
getIdentityProviderRepresentation(identityProviderAlias);
|
||||
|
||||
var restTemplate = new RestTemplate();
|
||||
var url = getKeycloakIdentityProviderInstancesUrl() + identityProviderAlias;
|
||||
var headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.add("Authorization", "Bearer " + getToken());
|
||||
HttpEntity<?> httpEntity = new HttpEntity<>(headers);
|
||||
try {
|
||||
restTemplate.exchange(url, HttpMethod.DELETE, httpEntity, String.class);
|
||||
} catch (HttpClientErrorException e) {
|
||||
throw new ResponseStatusException(e.getStatusCode(), extractKeycloakErrorMessageInfos(e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkIfOtherIdpHasSameDisplayNameOnUpdate(String alias, String displayName) {
|
||||
|
||||
checkIfOtherIdpHasSameDisplayName(getIdentityProviders().getIdentityProviders()
|
||||
.stream()
|
||||
.filter(identityProviderModel -> !identityProviderModel.getAlias().equals(alias))
|
||||
.toList(), displayName);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void checkIfOtherIdpHasSameDisplayNameOnCreate(String displayName) {
|
||||
|
||||
checkIfOtherIdpHasSameDisplayName(getIdentityProviders().getIdentityProviders(), displayName);
|
||||
}
|
||||
|
||||
|
||||
private void checkIfOtherIdpHasSameDisplayName(List<IdentityProviderModel> identityProviderModelList, String displayName) {
|
||||
|
||||
if (identityProviderModelList.stream()
|
||||
.anyMatch(idp -> idp.getDisplayName().isEmpty() ? idp.getAlias().equals(displayName) : idp.getDisplayName().equals(displayName))) {
|
||||
throw new ConflictException("Identity provider with this display name already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static String extractKeycloakErrorMessageInfos(String keyCloakErrorMessage) {
|
||||
|
||||
String errorMessageRegex = "\\{\"errorMessage\":\"(.*?)\"}";
|
||||
Pattern pattern = Pattern.compile(errorMessageRegex);
|
||||
Matcher matcher = pattern.matcher(keyCloakErrorMessage);
|
||||
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return keyCloakErrorMessage;
|
||||
}
|
||||
|
||||
|
||||
private String getTenantId() {
|
||||
|
||||
return TenantContext.getTenantId();
|
||||
}
|
||||
|
||||
|
||||
private RealmRepresentation getRealmRepresentation() {
|
||||
|
||||
return realmService.realm(getTenantId()).toRepresentation();
|
||||
}
|
||||
|
||||
|
||||
private String getKeycloakIdentityProviderInstancesUrl() {
|
||||
|
||||
return tenantUserManagementProperties.getServerUrl() + "/admin/realms/" + getTenantId() + "/identity-provider/instances/";
|
||||
}
|
||||
|
||||
|
||||
private String getToken() {
|
||||
|
||||
return keyCloakAdminClientService.getAdminClient().tokenManager().getAccessToken().getToken();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_SMTP_CONFIGURATION;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.WRITE_SMTP_CONFIGURATION;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.SMTPConfigurationResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPConfiguration;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SMTPResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.EmailService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.RealmService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.SMTPService;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class SMTPConfigurationController implements SMTPConfigurationResource, PublicResource {
|
||||
|
||||
private final RealmService realmService;
|
||||
private final EmailService emailService;
|
||||
private final SMTPService smtpService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_SMTP_CONFIGURATION + "')")
|
||||
public SMTPConfiguration getCurrentSMTPConfiguration() {
|
||||
|
||||
return smtpService.getSMTPConfiguration();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public void updateSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfigurationModel) {
|
||||
|
||||
if (!smtpService.canUpdateSMTPConfig()) {
|
||||
throw new BadRequestException("Current license does not allow updating the SMTP configuration!");
|
||||
}
|
||||
|
||||
smtpService.updateSMTPConfiguration(smtpConfigurationModel);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public SMTPResponse testSMTPConfiguration(@RequestBody SMTPConfiguration smtpConfiguration) {
|
||||
|
||||
String targetEmail = realmService.getEmail(realmService.realm(TenantContext.getTenantId()));
|
||||
boolean adminEmail = true;
|
||||
|
||||
if (StringUtils.isEmpty(targetEmail)) {
|
||||
// will send e-mail to self in case targetEmail is not set
|
||||
targetEmail = smtpConfiguration.getFrom();
|
||||
adminEmail = false;
|
||||
}
|
||||
|
||||
SMTPResponse.SMTPResponseBuilder smtpResponseBuilder = emailService.send(smtpService.convertSMTPConfigToMap(smtpConfiguration),
|
||||
targetEmail,
|
||||
"Redaction Test message",
|
||||
"This is a test message");
|
||||
SMTPResponse smtpResponse = smtpResponseBuilder.adminEmail(adminEmail).recipientEmail(targetEmail).build();
|
||||
log.info("Test SMTP Configuration status: {}, reason: {}, recipient: {}", smtpResponse.getStatusCode(), smtpResponse.getReasonPhrase(), smtpResponse.getRecipientEmail());
|
||||
return smtpResponse;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_SMTP_CONFIGURATION + "')")
|
||||
public void clearSMTPConfiguration() {
|
||||
|
||||
smtpService.createDefaultSMTPConfiguration();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
108
src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/TenantsController.java
vendored
Normal file
108
src/main/java/com/knecon/fforesight/tenantusermanagement/controller/external/TenantsController.java
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.CREATE_TENANT;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.DELETE_TENANT;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.DEPLOYMENT_INFO;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.GET_TENANTS;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.UPDATE_TENANT;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class TenantsController implements TenantsResource, PublicResource {
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
private final DeploymentKeyService deploymentKeyService;
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + CREATE_TENANT + "')")
|
||||
public void createTenant(@Valid @RequestBody CreateTenantRequest tenantRequest) {
|
||||
|
||||
try {
|
||||
tenantManagementService.createTenant(tenantRequest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DELETE_TENANT + "')")
|
||||
public void deleteTenant(String tenantId) {
|
||||
|
||||
try {
|
||||
tenantManagementService.deleteTenant(tenantId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_TENANTS + "')")
|
||||
public List<TenantResponse> getTenants() {
|
||||
|
||||
List<TenantResponse> tenants = tenantManagementService.getTenants();
|
||||
return tenants.stream().map(tenantManagementService::removePasswords).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + GET_TENANTS + "')")
|
||||
public TenantResponse getTenant(String tenantId) {
|
||||
|
||||
TenantResponse tenantResponse = tenantManagementService.getTenant(tenantId);
|
||||
return tenantManagementService.removePasswords(tenantResponse);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')")
|
||||
public TenantResponse updateTenant(String tenantId, @RequestBody UpdateTenantRequest tenantRequest) {
|
||||
|
||||
TenantResponse tenantResponse = tenantManagementService.updateTenant(tenantId, tenantRequest);
|
||||
return tenantManagementService.removePasswords(tenantResponse);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')")
|
||||
public void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request) {
|
||||
|
||||
tenantManagementService.updateDetails(tenantId, request);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DEPLOYMENT_INFO + "')")
|
||||
public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
||||
|
||||
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void syncTenant(@PathVariable(TENANT_ID_PARAM) String tenantId, @RequestBody JsonNode payload) {
|
||||
|
||||
tenantManagementService.syncTenant(tenantId, payload);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles.KNECON_ROLE_FILTER;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_ALL_USERS;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_USERS;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.UPDATE_MY_PROFILE;
|
||||
@ -18,13 +19,15 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.api.UserResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.UserResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateUserRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.ResetPasswordRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateMyProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantApplicationTypeService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.UserService;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
@ -34,10 +37,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class UserController implements UserResource {
|
||||
public class UserController implements UserResource, PublicResource {
|
||||
|
||||
|
||||
private final UserService userService;
|
||||
private final TenantUserManagementProperties tenantUserManagementProperties;
|
||||
private final TenantApplicationTypeService tenantApplicationTypeService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -47,9 +51,15 @@ public class UserController implements UserResource {
|
||||
if (bypassCache) {
|
||||
userService.evictUserCache();
|
||||
}
|
||||
var mappedRoles = tenantApplicationTypeService.getCurrentProperties().getKcRoleMapping().getAllRoles();
|
||||
|
||||
var allRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles();
|
||||
return userService.getAllUsers().stream().filter(user -> user.getRoles().stream().anyMatch(allRoles::contains)).collect(Collectors.toList());
|
||||
return userService.getAllUsers()
|
||||
.stream()
|
||||
.filter(user -> user.getRoles()
|
||||
.stream()
|
||||
.anyMatch(mappedRoles::contains))
|
||||
.filter(KNECON_ROLE_FILTER)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@ -61,23 +71,26 @@ public class UserController implements UserResource {
|
||||
userService.evictUserCache();
|
||||
}
|
||||
|
||||
return userService.getAllUsers();
|
||||
return userService.getAllUsers()
|
||||
.stream()
|
||||
.filter(KNECON_ROLE_FILTER)
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_USERS + "')")
|
||||
public void updateProfile(@PathVariable(USER_ID) String userId, @RequestBody UpdateProfileRequest updateProfileRequest) {
|
||||
public User updateProfile(@PathVariable(USER_ID) String userId, @RequestBody UpdateProfileRequest updateProfileRequest) {
|
||||
|
||||
this.userService.updateProfile(userId, updateProfileRequest);
|
||||
return this.userService.updateProfile(userId, updateProfileRequest);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + UPDATE_MY_PROFILE + "')")
|
||||
public void updateMyProfile(@Valid @RequestBody UpdateMyProfileRequest updateProfileRequest) {
|
||||
public User updateMyProfile(@Valid @RequestBody UpdateMyProfileRequest updateProfileRequest) {
|
||||
|
||||
this.userService.updateMyProfile(updateProfileRequest);
|
||||
return this.userService.updateMyProfile(updateProfileRequest);
|
||||
}
|
||||
|
||||
|
||||
@ -112,15 +125,28 @@ public class UserController implements UserResource {
|
||||
if (StringUtils.isEmpty(userId)) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "The userId should not be empty.");
|
||||
}
|
||||
return userService.getUserById(userId).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"));
|
||||
var user = userService.getUserById(userId)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found"));
|
||||
|
||||
Set<String> filteredRoles = user.getRoles()
|
||||
.stream()
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!user.getRoles().isEmpty() && filteredRoles.isEmpty()) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "User not found");
|
||||
}
|
||||
|
||||
user.setRoles(filteredRoles);
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + WRITE_USERS + "')")
|
||||
public void setRoles(@PathVariable(USER_ID) String userId, @RequestBody Set<String> roles) {
|
||||
public User setRoles(@PathVariable(USER_ID) String userId, @RequestBody Set<String> roles) {
|
||||
|
||||
userService.setRoles(userId, roles);
|
||||
return userService.setRoles(userId, roles);
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,27 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller;
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.UserPreferenceResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.UserPreferenceResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.UserService;
|
||||
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class UserPreferenceController implements UserPreferenceResource {
|
||||
public class UserPreferenceController implements UserPreferenceResource, PublicResource {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external.v2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.v2.PublicResourceV2;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.v2.UserResourceV2;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.external.v2.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.controller.external.UserController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "6. Users endpoints", description = "Operations related to users.")
|
||||
public class UserControllerV2 implements UserResourceV2, PublicResourceV2 {
|
||||
|
||||
private final UserController userController;
|
||||
|
||||
|
||||
public List<User> getUsers(@RequestParam(name = USERNAME_PARAM, required = false) String username) {
|
||||
|
||||
var users = userController.getApplicationSpecificUsers(false)
|
||||
.stream()
|
||||
.map(this::convertUser);
|
||||
|
||||
if (username == null) {
|
||||
return users.toList();
|
||||
}
|
||||
return users.filter(user -> user.getUsername().equals(username)).toList();
|
||||
}
|
||||
|
||||
|
||||
public User getUserById(@PathVariable(USER_ID) String userId) {
|
||||
return convertUser(userController.getUserById(userId));
|
||||
}
|
||||
|
||||
|
||||
private User convertUser(com.knecon.fforesight.tenantusermanagement.model.User user){
|
||||
return User.builder()
|
||||
.id(user.getUserId())
|
||||
.username(user.getUsername())
|
||||
.email(user.getEmail())
|
||||
.firstName(user.getFirstName())
|
||||
.lastName(user.getLastName())
|
||||
.active(user.isActive())
|
||||
.roles(user.getRoles())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,11 +8,15 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.knecon.fforesight.tenantcommons.TenantApplicationType;
|
||||
import com.knecon.fforesight.tenantcommons.model.TenantResponse;
|
||||
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
@ -21,16 +25,23 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class InternalTenantsController implements InternalTenantsResource {
|
||||
public class InternalTenantsController implements InternalTenantsResource, InternalResource {
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
private final DeploymentKeyService deploymentKeyService;
|
||||
|
||||
|
||||
public void createTenant(@Valid @RequestBody TenantRequest tenantRequest) {
|
||||
@Override
|
||||
public void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request) {
|
||||
|
||||
tenantManagementService.updateDetails(tenantId, request);
|
||||
}
|
||||
|
||||
|
||||
public TenantResponse createTenant(@Valid @RequestBody CreateTenantRequest tenantRequest) {
|
||||
|
||||
try {
|
||||
tenantManagementService.createTenant(tenantRequest);
|
||||
return tenantManagementService.createTenant(tenantRequest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
|
||||
}
|
||||
@ -43,15 +54,16 @@ public class InternalTenantsController implements InternalTenantsResource {
|
||||
}
|
||||
|
||||
|
||||
public TenantResponse getTenant(String tenantId) {
|
||||
public TenantResponse getTenant(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
||||
|
||||
return tenantManagementService.getTenant(tenantId);
|
||||
}
|
||||
|
||||
|
||||
public List<SimpleTenantResponse> getSimpleTenants() {
|
||||
@Override
|
||||
public TenantResponse updateTenant(String tenantId, UpdateTenantRequest tenantRequest) {
|
||||
|
||||
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
|
||||
return tenantManagementService.updateTenant(tenantId, tenantRequest);
|
||||
}
|
||||
|
||||
|
||||
@ -60,4 +72,18 @@ public class InternalTenantsController implements InternalTenantsResource {
|
||||
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void syncTenant(@PathVariable(TENANT_ID_PARAM) String tenantId, @RequestBody JsonNode payload) {
|
||||
|
||||
tenantManagementService.syncTenant(tenantId, payload);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public TenantApplicationType getTenantApplicationType(@PathVariable(TENANT_ID_PARAM) String tenantId) {
|
||||
|
||||
return tenantManagementService.getTenantApplicationType(tenantId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import java.util.List;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalUserResource;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.UserService;
|
||||
@ -15,7 +16,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class InternalUserController implements InternalUserResource {
|
||||
public class InternalUserController implements InternalUserResource, InternalResource {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.dev;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantUser;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
@Service
|
||||
@Profile("dev")
|
||||
@RequiredArgsConstructor
|
||||
public class DevApplicationRunner implements ApplicationRunner {
|
||||
|
||||
private final DevTestTenantService devTestTenantService;
|
||||
private final TenantManagementService tenantManagementService;
|
||||
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void run(ApplicationArguments args) {
|
||||
|
||||
devTestTenantService.createTestTenantIfNotExists("redaction", new ArrayList<>());
|
||||
tenantManagementService.syncTenant("redaction", null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.dev;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
@Configuration
|
||||
@Profile("dev")
|
||||
@EnableConfigurationProperties(DevTenantProperties.class)
|
||||
public class DevConfiguration {
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.dev;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties("dev.tenant")
|
||||
public class DevTenantProperties {
|
||||
|
||||
private boolean recreateTenant;
|
||||
private DevDatabaseProperties db = new DevDatabaseProperties();
|
||||
private DevStorageProperties storage = new DevStorageProperties();
|
||||
|
||||
@Data
|
||||
public static class DevStorageProperties {
|
||||
|
||||
private DevStorageMode mode = DevStorageMode.S3;
|
||||
private DevS3StorageProperties s3 = new DevS3StorageProperties();
|
||||
private DevAzureStorageProperties azure = new DevAzureStorageProperties();
|
||||
|
||||
}
|
||||
|
||||
public enum DevStorageMode {
|
||||
S3,
|
||||
AZURE
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DevS3StorageProperties {
|
||||
|
||||
private String key;
|
||||
private String secret;
|
||||
private String bucket;
|
||||
|
||||
private String endpoint;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DevAzureStorageProperties {
|
||||
|
||||
private String containerName;
|
||||
private String connectionString;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DevDatabaseProperties {
|
||||
|
||||
private int port;
|
||||
private String host;
|
||||
private String database;
|
||||
private String schema;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.dev;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.model.AzureStorageConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.DatabaseConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.S3StorageConnection;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SearchConnectionRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantUser;
|
||||
import com.knecon.fforesight.tenantusermanagement.repository.TenantRepository;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Profile("dev")
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DevTestTenantService {
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
private final TenantRepository tenantRepository;
|
||||
private final DataSource dataSource;
|
||||
@Value("${spring.datasource.url:}")
|
||||
private String masterJDBCURL;
|
||||
|
||||
private final DevTenantProperties devTenantProperties;
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createTestTenantIfNotExists(String tenantId, List<TenantUser> users) {
|
||||
|
||||
if (devTenantProperties.isRecreateTenant()) {
|
||||
tenantRepository.deleteByQuery(tenantId);
|
||||
}
|
||||
try {
|
||||
tenantManagementService.getTenant(tenantId);
|
||||
} catch (Exception e) {
|
||||
tenantRepository.deleteByQuery(tenantId);
|
||||
createTestTenant(tenantId, users);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createTestTenant(String tenantId, List<TenantUser> users) {
|
||||
|
||||
String tenantsDBName = "tenants";
|
||||
String tenantsDBPassword = "tenants";
|
||||
log.info("Creating Tenant {} ", tenantId);
|
||||
|
||||
var jdbcUrl = masterJDBCURL.substring(0, masterJDBCURL.lastIndexOf('/') + 1) + tenantsDBName + "?currentSchema=" + tenantId;
|
||||
|
||||
createDatabase(tenantsDBName, tenantsDBPassword);
|
||||
createSchema(jdbcUrl, tenantId, tenantsDBName, tenantsDBPassword);
|
||||
|
||||
var tenantRequest = CreateTenantRequest.builder()
|
||||
.tenantId(tenantId)
|
||||
.displayName(tenantId)
|
||||
.guid(UUID.randomUUID().toString())
|
||||
.defaultUsers(users != null ? users : new ArrayList<>())
|
||||
.databaseConnection(DatabaseConnection.builder()
|
||||
.driver("postgresql")
|
||||
.host(devTenantProperties.getDb().getHost())
|
||||
.port(devTenantProperties.getDb().getPort() + "")
|
||||
.database(devTenantProperties.getDb().getDatabase())
|
||||
.schema(devTenantProperties.getDb().getSchema())
|
||||
.username(devTenantProperties.getDb().getUsername())
|
||||
.password(devTenantProperties.getDb().getPassword())
|
||||
.build())
|
||||
.searchConnection(SearchConnectionRequest.builder()
|
||||
.hosts(Set.of("localhost"))
|
||||
.port(9200)
|
||||
.scheme("http")
|
||||
.numberOfShards("1")
|
||||
.numberOfReplicas("5")
|
||||
.build());
|
||||
|
||||
if (devTenantProperties.getStorage().getMode() == DevTenantProperties.DevStorageMode.S3) {
|
||||
tenantRequest.s3StorageConnection(S3StorageConnection.builder().key(devTenantProperties.getStorage().getS3().getKey())
|
||||
.secret(devTenantProperties.getStorage().getS3().getSecret())
|
||||
.region("eu-central-1")
|
||||
.bucketName(devTenantProperties.getStorage().getS3().getBucket()).endpoint(devTenantProperties.getStorage().getS3().getEndpoint()).build());
|
||||
} else {
|
||||
tenantRequest.azureStorageConnection(AzureStorageConnection.builder().connectionString(devTenantProperties.getStorage().getAzure().getConnectionString())
|
||||
.containerName(devTenantProperties.getStorage().getAzure().getContainerName()).build());
|
||||
}
|
||||
|
||||
tenantManagementService.createTenant(tenantRequest.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void createDatabase(String db, String password) {
|
||||
|
||||
var jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE DATABASE " + db));
|
||||
} catch (Exception e) {
|
||||
log.warn("DB already exists");
|
||||
}
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE USER " + db + " WITH ENCRYPTED PASSWORD '" + password + "'"));
|
||||
} catch (Exception e) {
|
||||
log.warn("user already exists");
|
||||
}
|
||||
try {
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT ALL PRIVILEGES ON DATABASE " + db + " TO " + db));
|
||||
} catch (Exception e) {
|
||||
log.warn("grant invalid");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createSchema(String jdbcUrl, String tenantName, String username, String password) {
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
JdbcTemplate insert = new JdbcTemplate(tenantDataSource);
|
||||
try {
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA " + tenantName));
|
||||
} catch (Exception e) {
|
||||
log.warn("schema already exists");
|
||||
}
|
||||
try {
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA " + tenantName + " TO " + username));
|
||||
} catch (Exception e) {
|
||||
log.warn("grant invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "global_smtp_configuration")
|
||||
public class GlobalSMTPConfigurationEntity {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false, updatable = false)
|
||||
private String id = "singleton";
|
||||
|
||||
@Column
|
||||
private Boolean auth;
|
||||
|
||||
@Column
|
||||
private String envelopeFrom;
|
||||
|
||||
@Column
|
||||
private String fromEmail;
|
||||
|
||||
@Column
|
||||
private String fromDisplayName;
|
||||
|
||||
@Column
|
||||
private String host;
|
||||
|
||||
@Column
|
||||
private String password;
|
||||
|
||||
@Column
|
||||
private Integer port;
|
||||
|
||||
@Column
|
||||
private String replyTo;
|
||||
|
||||
@Column
|
||||
private String replyToDisplayName;
|
||||
|
||||
@Column
|
||||
private Boolean ssl;
|
||||
|
||||
@Column
|
||||
private Boolean starttls;
|
||||
|
||||
@Column
|
||||
private String userName;
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.entity;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Embeddable
|
||||
public class MongoDBConnectionEntity {
|
||||
|
||||
@Column(name = "mongodb_prefix")
|
||||
private String prefix;
|
||||
@Column(name = "mongodb_username")
|
||||
private String username;
|
||||
@Column(name = "mongodb_password")
|
||||
private String password;
|
||||
@Column(name = "mongodb_address")
|
||||
private String address;
|
||||
@Column(name = "mongodb_database")
|
||||
private String database;
|
||||
@Column(name = "mongodb_options")
|
||||
private String options;
|
||||
|
||||
}
|
||||
@ -23,6 +23,7 @@ public class SearchConnectionEntity {
|
||||
@Convert(converter = JSONStringSetConverter.class)
|
||||
private Set<String> hosts;
|
||||
@Column(name = "search_port")
|
||||
@Builder.Default
|
||||
private int port = 9300;
|
||||
@Column(name = "search_scheme")
|
||||
private String scheme;
|
||||
@ -34,5 +35,7 @@ public class SearchConnectionEntity {
|
||||
private String numberOfShards;
|
||||
@Column(name = "search_number_of_replicas")
|
||||
private String numberOfReplicas;
|
||||
@Column(name = "search_index_prefix")
|
||||
private String indexPrefix;
|
||||
|
||||
}
|
||||
|
||||
@ -1,8 +1,19 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.TenantApplicationType;
|
||||
import com.knecon.fforesight.tenantusermanagement.utils.JSONMapConverter;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -37,4 +48,17 @@ public class TenantEntity {
|
||||
@Embedded
|
||||
private S3StorageConnectionEntity s3StorageConnection;
|
||||
|
||||
@Embedded
|
||||
private MongoDBConnectionEntity mongoDBConnection;
|
||||
|
||||
@Basic(fetch = FetchType.EAGER)
|
||||
@Column(columnDefinition = "text")
|
||||
@Convert(converter = JSONMapConverter.class)
|
||||
@Builder.Default
|
||||
private Map<String, Object> details = new HashMap<>();
|
||||
|
||||
@Column
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TenantApplicationType applicationType;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.events;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TenantSyncEvent {
|
||||
|
||||
private String tenantId;
|
||||
private JsonNode payload;
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.exception;
|
||||
|
||||
public class ConflictException extends RuntimeException {
|
||||
|
||||
public ConflictException(String message) {
|
||||
|
||||
super(message);
|
||||
}
|
||||
|
||||
|
||||
public ConflictException(String message, Throwable t) {
|
||||
|
||||
super(message, t);
|
||||
}
|
||||
|
||||
|
||||
public static ConflictException withObjectName(String objectName) {
|
||||
|
||||
return new ConflictException(String.format("An object of type %s already exists.", objectName));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.CONFLICT)
|
||||
public class IdentityProviderExistsAlreadyException extends ConflictException {
|
||||
|
||||
private static final String IDENTITY_PROVIDER_ALREADY_EXISTS_MESSAGE = "Identity provider with alias %s already exists in keycloak.";
|
||||
|
||||
public IdentityProviderExistsAlreadyException(String identityProviderAlias) {
|
||||
super(String.format(IDENTITY_PROVIDER_ALREADY_EXISTS_MESSAGE, identityProviderAlias));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.NOT_FOUND)
|
||||
public class IdentityProviderNotFoundException extends NotFoundException {
|
||||
|
||||
private static final String IDENTITY_PROVIDER_NOT_FOUND_MESSAGE = "Identity provider with alias %s not found in keycloak.";
|
||||
|
||||
public IdentityProviderNotFoundException(String identityProviderAlias) {
|
||||
super(String.format(IDENTITY_PROVIDER_NOT_FOUND_MESSAGE, identityProviderAlias));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.initializer;
|
||||
|
||||
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.TenantProvider;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.KeyCloakRoleManagerService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MigrateOnlyHook {
|
||||
|
||||
@Value("${fforesight.tenant-user-management.migrate-only:false}")
|
||||
private boolean isMigrateOnly;
|
||||
|
||||
private final ApplicationContext ctx;
|
||||
|
||||
private final TenantManagementService tenantManagementService;
|
||||
|
||||
private final KeyCloakRoleManagerService keyCloakRoleManagerService;
|
||||
|
||||
|
||||
@SuppressWarnings("PMD.DoNotTerminateVM")
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void migrate() {
|
||||
|
||||
tenantManagementService.getTenants().forEach(tenant -> keyCloakRoleManagerService.updateRoles(tenant.getTenantId(), tenant.getApplicationType()));
|
||||
|
||||
// This should only run in post upgrade hook
|
||||
if (isMigrateOnly) {
|
||||
System.exit(SpringApplication.exit(ctx, () -> 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -20,29 +20,10 @@ public class MessagingConfiguration {
|
||||
return new TopicExchange(tenantExchangeName);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
TopicExchange userExchange(@Value("${fforesight.user-exchange.name}") String userExchangeName) {
|
||||
|
||||
return new TopicExchange(userExchangeName);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
|
||||
|
||||
final var rabbitTemplate = new RabbitTemplate(connectionFactory);
|
||||
rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
|
||||
return rabbitTemplate;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper().findAndRegisterModules();
|
||||
|
||||
return new Jackson2JsonMessageConverter(mapper);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.knecon.fforesight.tenantcommons.TenantApplicationType;
|
||||
import com.knecon.fforesight.tenantcommons.model.AzureStorageConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.DatabaseConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.S3StorageConnection;
|
||||
import com.knecon.fforesight.tenantcommons.model.MongoDBConnection;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Object containing the request to create a tenant.")
|
||||
public class CreateTenantRequest {
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = "[A-Za-z0-9_-]*", message = "Tenant Id must match [A-Za-z0-9_-]")
|
||||
@Schema(description = "Parameter containing the ID of the tenant.")
|
||||
private String tenantId;
|
||||
@NotBlank
|
||||
@Schema(description = "Parameter containing the display name of the tenant.")
|
||||
private String displayName;
|
||||
@Schema(description = "Parameter containing the global unique ID of the tenant.")
|
||||
private String guid;
|
||||
|
||||
@Schema(description = "Parameter containing data of the database connection.")
|
||||
private DatabaseConnection databaseConnection;
|
||||
@Schema(description = "Parameter containing data of the search connection.")
|
||||
private SearchConnectionRequest searchConnection;
|
||||
@Schema(description = "Parameter containing data of the Azure storage connection.")
|
||||
private AzureStorageConnection azureStorageConnection;
|
||||
@Schema(description = "Parameter containing data of the S3 storage connection.")
|
||||
private S3StorageConnection s3StorageConnection;
|
||||
@Schema(description = "Parameter containing data of the MongoDB connection.")
|
||||
private MongoDBConnection mongoDBConnection;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Parameter containing a list of users of the tenant.")
|
||||
private List<TenantUser> defaultUsers = new ArrayList<>();
|
||||
|
||||
@Schema(description = "Parameter containing the application type of the tenant.")
|
||||
private TenantApplicationType applicationType;
|
||||
|
||||
}
|
||||
@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "Object containing the request to create a profile.")
|
||||
public class CreateUserRequest {
|
||||
|
||||
@Schema(description = "Email of user.")
|
||||
@ -21,7 +22,10 @@ public class CreateUserRequest {
|
||||
@Schema(description = "Last name of user.")
|
||||
private String lastName;
|
||||
|
||||
@Schema(description = "The list of RED_* roles.")
|
||||
@Schema(description = "Roles to assign to user.")
|
||||
private Set<String> roles = new HashSet<>();
|
||||
|
||||
@Schema(description = "Whether a set password mail should be sent")
|
||||
private boolean sendSetPasswordMail;
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -7,8 +8,10 @@ import lombok.NoArgsConstructor;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "Object containing data about the deployment key.")
|
||||
public class DeploymentKeyResponse {
|
||||
|
||||
@Schema(description = "Parameter containing the deployment key.")
|
||||
private String value;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
public class ErrorMessage {
|
||||
|
||||
private OffsetDateTime timestamp = OffsetDateTime.now();
|
||||
private final String message;
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ExtensibleModel {
|
||||
|
||||
void setNotMappedFields(Map<String, String> notMappedFields);
|
||||
Map<String, String> getNotMappedFields();
|
||||
|
||||
}
|
||||
@ -1,18 +1,25 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@EqualsAndHashCode
|
||||
@Schema(description = "Object containing data about general configurations.")
|
||||
public class GeneralConfigurationModel {
|
||||
|
||||
@Schema(description = "Parameter indicating if the 'ForgotPassword' function is enabled.")
|
||||
private boolean forgotPasswordFunctionEnabled;
|
||||
@Schema(description = "Parameter containing the auxiliary name.")
|
||||
private String auxiliaryName;
|
||||
@Schema(description = "Parameter containing the display name of the application.")
|
||||
private String displayName;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Object containing information about an identity provider configuration.")
|
||||
public class IdentityProviderConfigModel implements ExtensibleModel {
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Whether the external identity provider is allowed to create a new identifier to represent the principal")
|
||||
private Boolean allowCreate = true;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Display order : It defines the order of the providers in GUI (for example, on the Login page). The lowest number will be applied first.")
|
||||
private Integer guiOrder = 0;
|
||||
|
||||
@Schema(description = "Service provider entity ID : It is used to uniquely identify this SAML Service Provider.")
|
||||
private String entityId;
|
||||
|
||||
@Schema(description = "Identity provider entity ID : It is used to validate the Issuer for received SAML assertions. If empty, no Issuer validation is performed.")
|
||||
private String idpEntityId;
|
||||
|
||||
@Schema(description = "The Url that must be used to send authentication requests (SAML AuthnRequest).")
|
||||
private String singleSignOnServiceUrl;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "The Url that must be used to send logout requests.")
|
||||
private String singleLogoutServiceUrl = "";
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Name of the Attribute Consuming Service profile to advertise in the SP metadata.")
|
||||
private String attributeConsumingServiceName = "";
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Backchannel logout : Does the external IDP support backchannel logout?")
|
||||
private Boolean backchannelSupported = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Specifies the URI reference corresponding to a name identifier format.")
|
||||
private IdentityProviderNameIDPolicyFormat nameIDPolicyFormat = IdentityProviderNameIDPolicyFormat.PERSISTENT;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Used to identify and track external users from the assertion. Default is using Subject NameID, alternatively can be set up as identifying attribute.")
|
||||
private IdentityProviderPrincipalType principalType = IdentityProviderPrincipalType.SUBJECT;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "HTTP-POST binding response : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.")
|
||||
private Boolean postBindingResponse = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "HTTP-POST binding for AuthnRequest : Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.")
|
||||
private Boolean postBindingAuthnRequest = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "HTTP-POST binding logout : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.")
|
||||
private Boolean postBindingLogout = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Indicates whether the identity provider expects a signed AuthnRequest.")
|
||||
private Boolean wantAuthnRequestsSigned = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Indicates whether this service provider expects a signed Assertion.")
|
||||
private Boolean wantAssertionsSigned = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Indicates whether this service provider expects an encrypted Assertion.")
|
||||
private Boolean wantAssertionsEncrypted = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Force authentication : Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context.")
|
||||
private Boolean forceAuthn = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Enable/disable signature validation of external IDP signatures.")
|
||||
private Boolean validateSignature = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Sign service provider metadata : Enable/disable signature of the provider SAML metadata.")
|
||||
private Boolean signSpMetadata = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Pass subject : During login phase, forward an optional login_hint query parameter to SAML AuthnRequest's Subject.")
|
||||
private Boolean loginHint = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Clock skew in seconds that is tolerated when validating identity provider tokens. Default value is zero.")
|
||||
private Integer allowedClockSkew = 0;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Index of the Attribute Consuming Service profile to request during authentication.")
|
||||
private Integer attributeConsumingServiceIndex = 0;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "If hidden, login with this provider is possible only if requested explicitly, for example using the 'kc_idp_hint' parameter.")
|
||||
private Boolean hideOnLoginPage = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Default sync mode for all mappers. The sync mode determines when user data will be synced using the mappers. Possible values are: 'legacy' to keep the behaviour before this option was introduced, 'import' to only import the user once during first login of the user with this identity provider, 'force' to always update the user during every login with this identity provider.")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private IdentityProviderSyncMode syncMode = IdentityProviderSyncMode.IMPORT;
|
||||
|
||||
@Schema(description = "The signature algorithm to use to sign documents. Note that 'SHA1' based algorithms are deprecated and can be removed in the future. It is recommended to stick to some more secure algorithm instead of '*_SHA1'.")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private IdentityProviderSignatureAlgorithm signatureAlgorithm;
|
||||
|
||||
@Schema(description = "SAML signature key name : Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counter-party, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works.")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private IdentityProviderSAMLSignatureKeyName xmlSigKeyInfoKeyNameTransformer;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "All not mapped configurations")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private Map<String, String> notMappedFields = new HashMap<>();
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Create request for the identity provider configuration.")
|
||||
public class IdentityProviderConfigRequest {
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Whether the external identity provider is allowed to create a new identifier to represent the principal (default: true)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Boolean allowCreate = true;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Display order : It defines the order of the providers in GUI (for example, on the Login page). The lowest number will be applied first. (default: 0)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Integer guiOrder = 0;
|
||||
|
||||
@Schema(description = "Service provider entity ID : It is used to uniquely identify this SAML Service Provider.", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private String entityId;
|
||||
|
||||
@Schema(description = "Identity provider entity ID : It is used to validate the Issuer for received SAML assertions. If empty, no Issuer validation is performed.", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private String idpEntityId;
|
||||
|
||||
@Schema(description = "The Url that must be used to send authentication requests (SAML AuthnRequest).", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private String singleSignOnServiceUrl;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Specifies the URI reference corresponding to a name identifier format. (default: PERSISTENT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private IdentityProviderNameIDPolicyFormat nameIDPolicyFormat = IdentityProviderNameIDPolicyFormat.PERSISTENT;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Used to identify and track external users from the assertion. Default is using Subject NameID, alternatively can be set up as identifying attribute. (default: SUBJECT)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private IdentityProviderPrincipalType principalType = IdentityProviderPrincipalType.SUBJECT;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "HTTP-POST binding response : Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Boolean postBindingResponse = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "HTTP-POST binding for AuthnRequest : Indicates whether the AuthnRequest must be sent using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Boolean postBindingAuthnRequest = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Indicates whether the identity provider expects a signed AuthnRequest. (default: false)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private Boolean wantAuthnRequestsSigned = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "The signature algorithm to use to sign documents. Note that 'SHA1' based algorithms are deprecated and can be removed in the future. It is recommended to stick to some more secure algorithm instead of '*_SHA1'. (only used when wantAuthnRequestsSigned is true, default: RSA_SHA256)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private IdentityProviderSignatureAlgorithm signatureAlgorithm = IdentityProviderSignatureAlgorithm.RSA_SHA256;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "SAML signature key name : Signed SAML documents contain identification of signing key in KeyName element. For Keycloak / RH-SSO counter-party, use KEY_ID, for MS AD FS use CERT_SUBJECT, for others check and use NONE if no other option works. (only used when wantAuthnRequestsSigned is true, default: KEY_ID)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private IdentityProviderSAMLSignatureKeyName xmlSigKeyInfoKeyNameTransformer = IdentityProviderSAMLSignatureKeyName.KEY_ID;
|
||||
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -7,12 +10,10 @@ import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SimpleTenantResponse {
|
||||
|
||||
private String tenantId;
|
||||
private String displayName;
|
||||
private String guid;
|
||||
@AllArgsConstructor
|
||||
public class IdentityProviderList {
|
||||
|
||||
@Builder.Default
|
||||
private List<IdentityProviderModel> identityProviders = new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.Builder;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Object containing information about an identity provider.")
|
||||
public class IdentityProviderModel implements ExtensibleModel {
|
||||
|
||||
@Schema(description = "Alias of the identity provider used for identification")
|
||||
private String alias;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Configuration of the identity provider")
|
||||
private IdentityProviderConfigModel config = new IdentityProviderConfigModel();
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Display name of the identity provider in keycloak")
|
||||
private String displayName = "";
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "The ID of the SSO technology provider")
|
||||
private String providerId = "saml";
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Enable/disable if tokens must be stored after authenticating users.")
|
||||
private Boolean storeToken = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Stored tokens readable : Enable/disable if new users can read any stored tokens. This assigns the broker.read-token role.")
|
||||
private Boolean addReadTokenRoleOnCreate = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "If enabled, email provided by this provider is not verified even if verification is enabled for the realm.")
|
||||
private Boolean trustEmail = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Account linking only : If true, users cannot log in through this provider. They can only link to this provider. This is useful if you don't want to allow login from the provider, but want to integrate with a provider")
|
||||
private Boolean linkOnly = false;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "First login flow : Alias of authentication flow, which is triggered after first login with this identity provider. Term 'First Login' means that no Keycloak account is currently linked to the authenticated identity provider account.")
|
||||
private String firstBrokerLoginFlowAlias = "first broker login";
|
||||
|
||||
@Builder.Default
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private Map<String, String> notMappedFields = new HashMap<>();
|
||||
|
||||
|
||||
public void setSpecificDefaults() {
|
||||
|
||||
this.setStoreToken(true);
|
||||
this.setTrustEmail(true);
|
||||
this.getConfig().setSyncMode(IdentityProviderSyncMode.FORCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum IdentityProviderNameIDPolicyFormat {
|
||||
PERSISTENT("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"),
|
||||
TRANSIENT("urn:oasis:names:tc:SAML:2.0:nameid-format:transient"),
|
||||
EMAIL("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"),
|
||||
KERBEROS("urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos"),
|
||||
X_509_SUBJECT_NAME("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName"),
|
||||
WINDOWS_DOMAIN_QUALIFIED_NAME("urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName"),
|
||||
UNSPECIFIED("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified");
|
||||
|
||||
private final String representation;
|
||||
|
||||
|
||||
IdentityProviderNameIDPolicyFormat(String representation) {
|
||||
|
||||
this.representation = representation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
|
||||
return representation;
|
||||
}
|
||||
|
||||
public static IdentityProviderNameIDPolicyFormat fromRepresentation(String value) {
|
||||
|
||||
for (IdentityProviderNameIDPolicyFormat v : values()) {
|
||||
if (v.getRepresentation().equalsIgnoreCase(value)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
throw new BadRequestException("Unsupported identity provider name ID policy format");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
|
||||
public enum IdentityProviderPrincipalType {
|
||||
SUBJECT,
|
||||
ATTRIBUTE,
|
||||
FRIENDLY_ATTRIBUTE;
|
||||
|
||||
|
||||
public static IdentityProviderPrincipalType fromStringValue(String value) {
|
||||
|
||||
for (IdentityProviderPrincipalType v : values()) {
|
||||
if (v.toString().equalsIgnoreCase(value)) {
|
||||
return v;
|
||||
}
|
||||
if (value.equalsIgnoreCase("Subject NameID")) {
|
||||
return SUBJECT;
|
||||
}
|
||||
}
|
||||
throw new BadRequestException("Unsupported identity provider principal type");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Create or update request for an identity provider.")
|
||||
public class IdentityProviderRequest {
|
||||
|
||||
@Schema(description = "Alias of the identity provider used for identification", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String alias;
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Configuration of the identity provider", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private @Valid IdentityProviderConfigRequest config = new IdentityProviderConfigRequest();
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "Display name of the identity provider in keycloak (optional, fallbacks to alias if empty)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String displayName = "";
|
||||
|
||||
@Builder.Default
|
||||
@Schema(description = "The ID of the SSO technology provider (default: saml)", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String providerId = "saml";
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
public enum IdentityProviderSAMLSignatureKeyName {
|
||||
NONE,
|
||||
KEY_ID,
|
||||
CERT_SUBJECT
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.model;
|
||||
|
||||
public enum IdentityProviderSignatureAlgorithm {
|
||||
RSA_SHA1,
|
||||
RSA_SHA256,
|
||||
RSA_SHA256_MGF1,
|
||||
RSA_SHA512,
|
||||
RSA_SHA512_MGF1,
|
||||
DSA_SHA1
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user