git_diff.txt 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634
  1. diff --git a/.gitignore b/.gitignore
  2. index 7e57cb3..8994b5d 100644
  3. --- a/.gitignore
  4. +++ b/.gitignore
  5. @@ -1,2 +1,3 @@
  6. data/
  7. -config/nextcloud/
  8. \ No newline at end of file
  9. +config/credentials
  10. +config/nextcloud/
  11. diff --git a/ansible/site.yml b/ansible/site.yml
  12. index 22ea670..ded0d95 100644
  13. --- a/ansible/site.yml
  14. +++ b/ansible/site.yml
  15. @@ -1,11 +1,22 @@
  16. -# automated-office/ansible/site.yml
  17. ---
  18. - name: Deploy Automated Office
  19. - hosts: all
  20. + hosts: localhost
  21. become: true
  22. + pre_tasks:
  23. + - debug:
  24. + msg:
  25. + - "Client secret defined: {{ client_secret is defined }}"
  26. + - "Client secret length: {{ client_secret | default('') | length }}"
  27. + verbosity: 1
  28. +
  29. + - name: "Verify required variables"
  30. + fail:
  31. + msg: "Client secret is not set or empty"
  32. + when: client_secret is not defined or client_secret | default('') | trim == ''
  33. +
  34. roles:
  35. - - common
  36. - - docker
  37. - - nginx
  38. - - services
  39. \ No newline at end of file
  40. + - role: common
  41. + - role: docker
  42. + - role: nginx
  43. + - role: services
  44. \ No newline at end of file
  45. diff --git a/config/credentials/credentials_2024-12-11_18-28-21.txt.gpg b/config/credentials/credentials_2024-12-11_18-28-21.txt.gpg
  46. deleted file mode 100644
  47. index b43471e..0000000
  48. Binary files a/config/credentials/credentials_2024-12-11_18-28-21.txt.gpg and /dev/null differ
  49. diff --git a/config/nginx/sites-available/keycloak b/config/nginx/sites-available/keycloak
  50. index 2c2181a..cf437a2 100644
  51. --- a/config/nginx/sites-available/keycloak
  52. +++ b/config/nginx/sites-available/keycloak
  53. @@ -5,7 +5,7 @@ upstream keycloak_upstream {
  54. server {
  55. listen 80;
  56. server_name auth.mrx8086.com;
  57. -
  58. +
  59. # Redirect HTTP to HTTPS
  60. return 301 https://$host$request_uri;
  61. }
  62. @@ -30,35 +30,49 @@ server {
  63. add_header X-XSS-Protection "1; mode=block" always;
  64. add_header X-Frame-Options SAMEORIGIN always;
  65. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  66. -
  67. +
  68. # Content Security Policy
  69. add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; frame-src 'self'; frame-ancestors 'self'; connect-src 'self'" always;
  70. - # Proxy settings for all locations
  71. + # Proxy settings - Added X-Forwarded headers here to apply to all proxied locations
  72. proxy_set_header X-Real-IP $remote_addr;
  73. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  74. proxy_set_header X-Forwarded-Proto $scheme;
  75. + proxy_set_header X-Forwarded-Ssl on; # Optional, but explicit
  76. + proxy_set_header X-Forwarded-Port $server_port;
  77. proxy_set_header X-Forwarded-Host $host;
  78. - proxy_set_header X-Forwarded-Port 443;
  79. proxy_set_header Host $host;
  80. proxy_http_version 1.1;
  81. -
  82. +
  83. # Root location for the main application
  84. location / {
  85. proxy_pass http://keycloak_upstream;
  86. }
  87. + # Specific location for the token endpoint
  88. + location ~ ^/auth/realms/[^/]+/protocol/openid-connect/token$ {
  89. + proxy_pass http://keycloak_upstream;
  90. + proxy_buffer_size 128k;
  91. + proxy_buffers 4 256k;
  92. + proxy_busy_buffers_size 256k;
  93. + # WebSocket support (likely not needed for token endpoint, but keeping for consistency)
  94. + proxy_set_header Upgrade $http_upgrade;
  95. + proxy_set_header Connection "upgrade";
  96. + # Timeouts
  97. + proxy_connect_timeout 60s;
  98. + proxy_send_timeout 60s;
  99. + proxy_read_timeout 60s;
  100. + }
  101. +
  102. # Keycloak required paths
  103. location /realms/ {
  104. proxy_pass http://keycloak_upstream;
  105. proxy_buffer_size 128k;
  106. proxy_buffers 4 256k;
  107. proxy_busy_buffers_size 256k;
  108. -
  109. # WebSocket support
  110. proxy_set_header Upgrade $http_upgrade;
  111. proxy_set_header Connection "upgrade";
  112. -
  113. # Timeouts
  114. proxy_connect_timeout 60s;
  115. proxy_send_timeout 60s;
  116. @@ -67,7 +81,7 @@ server {
  117. location /resources/ {
  118. proxy_pass http://keycloak_upstream;
  119. -
  120. +
  121. # Cache settings for static resources
  122. proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
  123. proxy_cache_valid 200 1d;
  124. diff --git a/config/nginx/sites-available/nextcloud b/config/nginx/sites-available/nextcloud
  125. index c384e10..8357df3 100644
  126. --- a/config/nginx/sites-available/nextcloud
  127. +++ b/config/nginx/sites-available/nextcloud
  128. @@ -1,12 +1,10 @@
  129. upstream nextcloud_upstream {
  130. - server 172.19.0.3:80; # Die IP wird später durch die tatsächliche Container-IP ersetzt
  131. + server 172.19.0.3:80; # SICHERSTELLEN, DASS DIES DIE KORREKTE IP IST
  132. }
  133. server {
  134. listen 80;
  135. server_name cloud.mrx8086.com;
  136. -
  137. - # Redirect HTTP to HTTPS
  138. return 301 https://$host$request_uri;
  139. }
  140. @@ -14,27 +12,19 @@ server {
  141. listen 443 ssl;
  142. server_name cloud.mrx8086.com;
  143. - # SSL Configuration
  144. + # SSL Configuration (wie zuvor)
  145. ssl_certificate /etc/nginx/ssl/mrx8086.com/fullchain.pem;
  146. ssl_certificate_key /etc/nginx/ssl/mrx8086.com/privkey.pem;
  147. - ssl_session_timeout 1d;
  148. - ssl_session_tickets off;
  149. + # ... weitere SSL-Einstellungen ...
  150. - # Modern SSL configuration
  151. - ssl_protocols TLSv1.2 TLSv1.3;
  152. - ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  153. - ssl_prefer_server_ciphers off;
  154. -
  155. - # Security headers
  156. + # Security headers (wie zuvor)
  157. add_header X-Content-Type-Options nosniff always;
  158. add_header X-XSS-Protection "1; mode=block" always;
  159. add_header X-Frame-Options SAMEORIGIN always;
  160. add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  161. -
  162. - # Content Security Policy für Nextcloud
  163. add_header Content-Security-Policy "frame-ancestors 'self'; default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; media-src 'self';" always;
  164. - # Proxy settings
  165. + # Proxy settings (wie zuvor)
  166. proxy_set_header X-Real-IP $remote_addr;
  167. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  168. proxy_set_header X-Forwarded-Proto $scheme;
  169. @@ -43,31 +33,36 @@ server {
  170. proxy_set_header Host $host;
  171. proxy_http_version 1.1;
  172. - # Nextcloud specific settings
  173. + # Nextcloud specific settings (wie zuvor)
  174. client_max_body_size 512M;
  175. fastcgi_buffers 64 4K;
  176. -
  177. +
  178. + # Expliziter location-Block für den OpenID Connect Callback
  179. + location /apps/sociallogin/custom_oidc/keycloak {
  180. + proxy_pass http://nextcloud_upstream;
  181. + proxy_set_header Host $host;
  182. + proxy_set_header X-Real-IP $remote_addr;
  183. + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  184. + proxy_set_header X-Forwarded-Proto $scheme;
  185. + }
  186. +
  187. # Root location
  188. location / {
  189. proxy_pass http://nextcloud_upstream;
  190. -
  191. - # WebSocket support
  192. proxy_set_header Upgrade $http_upgrade;
  193. proxy_set_header Connection "upgrade";
  194. -
  195. - # Timeouts
  196. proxy_connect_timeout 60s;
  197. proxy_send_timeout 60s;
  198. proxy_read_timeout 60s;
  199. }
  200. - # Block sensitive paths
  201. + # Block sensitive paths (wie zuvor)
  202. location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) {
  203. deny all;
  204. return 404;
  205. }
  206. - # Deny access to hidden files
  207. + # Deny access to hidden files (wie zuvor)
  208. location ~ /\. {
  209. deny all;
  210. return 404;
  211. diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
  212. index 0163334..ccbcd3b 100644
  213. --- a/docker/docker-compose.yml
  214. +++ b/docker/docker-compose.yml
  215. @@ -34,8 +34,10 @@ services:
  216. - keycloak-network
  217. depends_on:
  218. - keycloak-db
  219. + extra_hosts:
  220. + - "cloud.mrx8086.com:172.23.171.133"
  221. healthcheck:
  222. - test: ["CMD", "curl", "-f", "http://localhost:8080/health/ready"]
  223. + test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
  224. interval: 30s
  225. timeout: 10s
  226. retries: 3
  227. @@ -48,7 +50,7 @@ services:
  228. POSTGRES_USER: ${KC_DB_USERNAME}
  229. POSTGRES_PASSWORD: ${KC_DB_PASSWORD}
  230. volumes:
  231. - - ../data/keycloak/db:/var/lib/postgresql/data
  232. + - ../data/keycloak-db:/var/lib/postgresql/data
  233. networks:
  234. - keycloak-network
  235. restart: unless-stopped
  236. @@ -63,6 +65,13 @@ services:
  237. image: nextcloud:latest
  238. container_name: nextcloud
  239. restart: unless-stopped
  240. + ports:
  241. + - "8081:80"
  242. + volumes:
  243. + - ../data/nextcloud:/var/www/html
  244. + - ../config/nextcloud/config:/var/www/html/config
  245. + - ../config/nextcloud/custom_apps:/var/www/html/custom_apps
  246. + - ../data/nextcloud-db:/var/lib/mysql
  247. environment:
  248. - MYSQL_HOST=nextcloud-db
  249. - MYSQL_DATABASE=nextcloud
  250. @@ -74,16 +83,24 @@ services:
  251. - OVERWRITEPROTOCOL=https
  252. - OVERWRITEHOST=cloud.mrx8086.com
  253. - OVERWRITEWEBROOT=/
  254. - - TRUSTED_PROXIES=172.18.0.0/16
  255. - volumes:
  256. - - ../data/nextcloud:/var/www/html
  257. - - ../config/nextcloud/config:/var/www/html/config
  258. - - ../config/nextcloud/custom_apps:/var/www/html/custom_apps
  259. - - ../config/nextcloud/data:/var/www/html/data
  260. + - TRUSTED_PROXIES=172.19.0.0/16
  261. + - NEXTCLOUD_URL=https://cloud.mrx8086.com
  262. + - NEXTCLOUD_DEBUG=1
  263. + - NEXTCLOUD_CONFIG_CUSTOM_SCOPE="openid profile groups-nextcloud"
  264. + healthcheck:
  265. + test: ["CMD", "curl", "-f", "http://localhost:80/"]
  266. + interval: 30s
  267. + timeout: 10s
  268. + retries: 3
  269. networks:
  270. - nextcloud-network
  271. depends_on:
  272. - nextcloud-db
  273. + extra_hosts:
  274. + - "auth.mrx8086.com:172.23.171.133"
  275. + dns:
  276. + - 8.8.8.8
  277. + - 8.8.4.4
  278. nextcloud-db:
  279. image: mariadb:10.6
  280. diff --git a/docs/context/scripts/setup_environment.sh b/docs/context/scripts/setup_environment.sh
  281. index 9a1b2da..1244eb8 100644
  282. --- a/docs/context/scripts/setup_environment.sh
  283. +++ b/docs/context/scripts/setup_environment.sh
  284. @@ -1,4 +1,5 @@
  285. #!/bin/bash
  286. +set -e
  287. # Ensure we're in the project root directory
  288. PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
  289. @@ -8,7 +9,8 @@ cd "${PROJECT_ROOT}"
  290. CREDENTIALS_DIR="config/credentials"
  291. DOCKER_DIR="docker"
  292. KEYCLOAK_SCRIPTS_DIR="scripts/setup/keycloak"
  293. -
  294. +ANSIBLE_PLAYBOOK="ansible/site.yml"
  295. +ANSIBLE_INVENTORY="ansible/inventory/staging/hosts"
  296. # Create necessary directories
  297. mkdir -p "${CREDENTIALS_DIR}"
  298. @@ -33,7 +35,7 @@ NEXTCLOUD_DB_USER=$(generate_password)
  299. NEXTCLOUD_DB_PASSWORD=$(generate_password)
  300. NEXTCLOUD_ADMIN_USER=$(generate_password)
  301. NEXTCLOUD_ADMIN_PASSWORD=$(generate_password)
  302. -
  303. +KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(generate_password)
  304. # Create .env file in docker directory
  305. cat > "${DOCKER_DIR}/.env" << EOL
  306. @@ -64,6 +66,7 @@ PAPERLESS_CLIENT_ID=paperless
  307. NODERED_CLIENT_ID=nodered
  308. TESTADMIN_PASSWORD=${TESTADMIN_PASSWORD}
  309. TESTUSER_PASSWORD=${TESTUSER_PASSWORD}
  310. +KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}
  311. EOL
  312. # Create encrypted credentials documentation
  313. @@ -77,8 +80,10 @@ Password: ${KEYCLOAK_ADMIN_PASSWORD}
  314. Keycloak Database Credentials:
  315. Username: keycloak
  316. Password: ${KC_DB_PASSWORD}
  317. +
  318. Test Admin Credentials:
  319. Password: ${TESTADMIN_PASSWORD}
  320. +
  321. Test User Credentials:
  322. Password: ${TESTUSER_PASSWORD}
  323. @@ -86,6 +91,7 @@ Nextcloud Database Credentials:
  324. Root Password: ${NEXTCLOUD_DB_ROOT_PASSWORD}
  325. User: ${NEXTCLOUD_DB_USER}
  326. Password: ${NEXTCLOUD_DB_PASSWORD}
  327. +
  328. Nextcloud Admin Credentials:
  329. Username: ${NEXTCLOUD_ADMIN_USER}
  330. Password: ${NEXTCLOUD_ADMIN_PASSWORD}
  331. @@ -101,4 +107,40 @@ echo ".env file for docker-compose has been created in: ${DOCKER_DIR}/.env"
  332. echo ".env file for setup_realm.js has been created in: ${KEYCLOAK_SCRIPTS_DIR}/.env"
  333. echo ""
  334. echo "To view credentials, use:"
  335. -echo "gpg -d ${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
  336. \ No newline at end of file
  337. +echo "gpg -d ${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
  338. +
  339. +echo ">>> Nextcloud Konfiguration..."
  340. +
  341. +# Verify if variable is set from earlier in the script
  342. +echo ">>> Debug: Checking original variable..."
  343. +echo ">>> Debug: KEYCLOAK_NEXTCLOUD_CLIENT_SECRET = ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}"
  344. +
  345. +# Try reading from .env file if variable is empty
  346. +if [ -z "${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}" ]; then
  347. + echo ">>> Debug: Variable is empty, trying to read from .env file..."
  348. + KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(grep KEYCLOAK_NEXTCLOUD_CLIENT_SECRET "${KEYCLOAK_SCRIPTS_DIR}/.env" | cut -d '=' -f2)
  349. + echo ">>> Debug: Value from .env file = ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}"
  350. +fi
  351. +
  352. +# Ensure we have a value
  353. +if [ -z "${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}" ]; then
  354. + echo ">>> Error: Could not get client secret value"
  355. + exit 1
  356. +fi
  357. +
  358. +# Escape special characters in the secret for JSON
  359. +ESCAPED_SECRET=$(echo "$KEYCLOAK_NEXTCLOUD_CLIENT_SECRET" | sed 's/["\]/\\&/g')
  360. +echo ">>> Debug: Escaped secret = $ESCAPED_SECRET"
  361. +
  362. +# Create the extra vars
  363. +EXTRA_VARS="{\"client_secret\": \"$ESCAPED_SECRET\"}"
  364. +echo ">>> Debug: Extra vars = $EXTRA_VARS"
  365. +
  366. +# Run Ansible with the extra vars
  367. +sudo ansible-playbook \
  368. + -i "$ANSIBLE_INVENTORY" \
  369. + "$ANSIBLE_PLAYBOOK" \
  370. + --extra-vars "$EXTRA_VARS" \
  371. + -v
  372. +
  373. +echo ">>> Fertig"
  374. \ No newline at end of file
  375. diff --git a/scripts/install/setup_environment.sh b/scripts/install/setup_environment.sh
  376. old mode 100644
  377. new mode 100755
  378. index aba63dc..5b7bc0e
  379. --- a/scripts/install/setup_environment.sh
  380. +++ b/scripts/install/setup_environment.sh
  381. @@ -1,31 +1,163 @@
  382. #!/bin/bash
  383. +set -e
  384. # Ensure we're in the project root directory
  385. PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
  386. -cd "${PROJECT_ROOT}"
  387. # Define directories relative to project root
  388. -CREDENTIALS_DIR="config/credentials"
  389. -DOCKER_DIR="docker"
  390. +CREDENTIALS_DIR="${PROJECT_ROOT}/config/credentials"
  391. +DOCKER_DIR="${PROJECT_ROOT}/docker"
  392. +KEYCLOAK_SETUP_DIR="${PROJECT_ROOT}/scripts/setup/keycloak"
  393. +ANSIBLE_PLAYBOOK="${PROJECT_ROOT}/ansible/site.yml"
  394. +ANSIBLE_INVENTORY="${PROJECT_ROOT}/ansible/inventory/staging/hosts"
  395. +NEXTCLOUD_DATA_DIR="${PROJECT_ROOT}/data/nextcloud/data"
  396. +TEMP_FILE=$(mktemp)
  397. +KEYCLOAK_DB_DIR="${PROJECT_ROOT}/data/keycloak-db"
  398. # Create necessary directories
  399. -mkdir -p "${CREDENTIALS_DIR}"
  400. -mkdir -p "${DOCKER_DIR}"
  401. +sudo mkdir -p "${CREDENTIALS_DIR}"
  402. +sudo mkdir -p "${DOCKER_DIR}"
  403. +sudo mkdir -p "${KEYCLOAK_SETUP_DIR}"
  404. +
  405. +# Initialize password variables
  406. +KEYCLOAK_ADMIN_PASSWORD=""
  407. +KC_DB_PASSWORD=""
  408. +TESTADMIN_PASSWORD=""
  409. +TESTUSER_PASSWORD=""
  410. +TESTSERVICEUSER_PASSWORD=""
  411. +KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=""
  412. +
  413. +# Function to read a password from a .env file
  414. +read_password_from_env() {
  415. + local env_file="$1"
  416. + local variable_name="$2"
  417. + if [ -f "$env_file" ]; then
  418. + grep "^${variable_name}=" "$env_file" | cut -d '=' -f2
  419. + fi
  420. +}
  421. # Function to generate secure passwords
  422. generate_password() {
  423. - openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 24
  424. + openssl rand -base64 32
  425. +}
  426. +
  427. +# Function to generate password if empty
  428. +generate_password_if_empty() {
  429. + local variable_name="$1"
  430. + eval "local value=\$$variable_name"
  431. + if [ -z "$value" ]; then
  432. + eval "$variable_name=\"$(generate_password)\""
  433. + echo ">>> Generiertes Passwort für: $variable_name"
  434. + fi
  435. +}
  436. +
  437. +# Function to create .env file
  438. +create_env_file() {
  439. + local env_file="$1"
  440. + local content="$2"
  441. + if [ ! -f "$env_file" ]; then
  442. + echo "$content" > "$env_file"
  443. + echo ">>> .env file created: $env_file"
  444. + else
  445. + echo ">>> .env file already exists: $env_file"
  446. + fi
  447. }
  448. +echo ">>> Überprüfe bestehende .env Dateien und lese Passwörter..."
  449. +
  450. +# Try reading passwords from existing .env files
  451. +if [ -f "$DOCKER_DIR/.env" ]; then
  452. + KC_DB_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KC_DB_PASSWORD")
  453. + KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD")
  454. +fi
  455. +
  456. +if [ -f "$KEYCLOAK_SETUP_DIR/.env" ]; then
  457. + KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD") # Überschreibt ggf. den Wert aus docker/.env
  458. + TESTADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTADMIN_PASSWORD")
  459. + TESTUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTUSER_PASSWORD")
  460. + TESTSERVICEUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTSERVICEUSER_PASSWORD")
  461. + KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_NEXTCLOUD_CLIENT_SECRET")
  462. +fi
  463. +
  464. +echo ">>> Generiere neue Passwörter für fehlende Werte..."
  465. +
  466. +# Generate passwords if they are still empty
  467. +generate_password_if_empty KEYCLOAK_ADMIN_PASSWORD
  468. +generate_password_if_empty KC_DB_PASSWORD
  469. +generate_password_if_empty TESTADMIN_PASSWORD
  470. +generate_password_if_empty TESTUSER_PASSWORD
  471. +generate_password_if_empty TESTSERVICEUSER_PASSWORD
  472. +generate_password_if_empty KEYCLOAK_NEXTCLOUD_CLIENT_SECRET
  473. +
  474. # Date for documentation
  475. SETUP_DATE=$(date '+%Y-%m-%d_%H-%M-%S')
  476. -# Generate passwords
  477. -KEYCLOAK_ADMIN_PASSWORD=$(generate_password)
  478. -KC_DB_PASSWORD=$(generate_password)
  479. +# Create credentials content
  480. +CREDENTIALS_CONTENT=$(cat <<EOL
  481. +Setup Date: ${SETUP_DATE}
  482. +
  483. +Keycloak Admin Credentials:
  484. +Username: admin
  485. +Password: ${KEYCLOAK_ADMIN_PASSWORD}
  486. +
  487. +Keycloak Database Credentials:
  488. +Username: keycloak
  489. +Password: ${KC_DB_PASSWORD}
  490. +
  491. +Test User Credentials:
  492. +Admin Password: ${TESTADMIN_PASSWORD}
  493. +User Password: ${TESTUSER_PASSWORD}
  494. +Service User Password: ${TESTSERVICEUSER_PASSWORD}
  495. +Nextcloud Client Secret: ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}
  496. +
  497. +EOL
  498. +)
  499. +
  500. +# Store credentials hash
  501. +CREDENTIALS_HASH=$(echo "$CREDENTIALS_CONTENT" | sha256sum | awk '{print $1}')
  502. +echo "$CREDENTIALS_HASH" > "${CREDENTIALS_DIR}/credentials_hash.txt"
  503. +echo ">>> Credentials hash stored in: ${CREDENTIALS_DIR}/credentials_hash.txt"
  504. +
  505. +# Set GPG PASSPHRASE
  506. +export GPG_PASSPHRASE=$(generate_password)
  507. +# Set GPG agent environment variable
  508. +export GPG_TTY=$(tty)
  509. +
  510. +echo ">>> Trying openssl encryption first"
  511. +# Alternative Verschlüsselung mit Openssl
  512. +echo "$CREDENTIALS_CONTENT" > "$TEMP_FILE"
  513. + if openssl enc -aes-256-cbc -pbkdf2 -salt -in "$TEMP_FILE" -out "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" -k "$GPG_PASSPHRASE" ; then
  514. + echo ">>> Credentials encrypted successfully using openssl"
  515. + mv "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
  516. + else
  517. + echo ">>> Openssl encryption failed, trying gpg"
  518. +
  519. + # Attempt to kill existing gpg agent
  520. + gpgconf --kill gpg-agent 2>/dev/null
  521. + echo ">>> Attempting to manually start gpg-agent with pinentry-curses"
  522. + gpg-agent --daemon --pinentry-program /usr/bin/pinentry-curses
  523. + gpg-connect-agent /bye 2>/dev/null
  524. + eval $(gpg-agent --daemon)
  525. + gpg-connect-agent updatestartuptty /bye 2>/dev/null
  526. +
  527. + # Attempt to encrypt credentials using GPG with error handling
  528. + if echo "$CREDENTIALS_CONTENT" | gpg --symmetric --cipher-algo AES256 -vvv -o "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg" ; then
  529. + echo ">>> Credentials encrypted successfully using gpg."
  530. + else
  531. + echo ">>> GPG encryption failed. Attempting GPG encryption with password workaround."
  532. + # Attempt encryption with passphrase workaround
  533. + if echo "$CREDENTIALS_CONTENT" | gpg --batch --passphrase "$GPG_PASSPHRASE" --symmetric --cipher-algo AES256 -vvv -o "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"; then
  534. + echo ">>> Credentials encrypted successfully using gpg with passphrase workaround."
  535. + else
  536. + echo ">>> GPG encryption with passphrase workaround failed"
  537. + exit 1
  538. + fi
  539. + fi
  540. + fi
  541. +rm "$TEMP_FILE"
  542. # Create .env file in docker directory
  543. -cat > "${DOCKER_DIR}/.env" << EOL
  544. +DOCKER_ENV_CONTENT=$(cat <<EOL
  545. # Generated on ${SETUP_DATE}
  546. # Keycloak Admin
  547. KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
  548. @@ -34,27 +166,69 @@ KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
  549. KC_DB_USERNAME=keycloak
  550. KC_DB_PASSWORD=${KC_DB_PASSWORD}
  551. EOL
  552. +)
  553. +create_env_file "$DOCKER_DIR/.env" "$DOCKER_ENV_CONTENT"
  554. -# Create encrypted credentials documentation
  555. -cat > "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt" << EOL
  556. -Setup Date: ${SETUP_DATE}
  557. +# Create .env file in scripts/setup/keycloak directory
  558. +KEYCLOAK_ENV_CONTENT=$(cat <<EOL
  559. +KEYCLOAK_URL=https://auth.mrx8086.com
  560. +KEYCLOAK_ADMIN_USER=admin
  561. +KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
  562. +NEXTCLOUD_CLIENT_ID=nextcloud
  563. +PAPERLESS_CLIENT_ID=paperless
  564. +NODERED_CLIENT_ID=nodered
  565. +TESTADMIN_PASSWORD=${TESTADMIN_PASSWORD}
  566. +TESTUSER_PASSWORD=${TESTUSER_PASSWORD}
  567. +TESTSERVICEUSER_PASSWORD=${TESTSERVICEUSER_PASSWORD}
  568. +KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}
  569. +EOL
  570. +)
  571. +create_env_file "$KEYCLOAK_SETUP_DIR/.env" "$KEYCLOAK_ENV_CONTENT"
  572. -Keycloak Admin Credentials:
  573. -Username: admin
  574. -Password: ${KEYCLOAK_ADMIN_PASSWORD}
  575. +echo ">>> Environment setup completed!"
  576. -Keycloak Database Credentials:
  577. -Username: keycloak
  578. -Password: ${KC_DB_PASSWORD}
  579. -EOL
  580. +# --------------- KEYCLOAK KONFIGURATION ---------------
  581. +echo ">>> Keycloak Konfiguration..."
  582. +cd "$KEYCLOAK_SETUP_DIR"
  583. +
  584. +echo ">>> Starte setup_realm.js"
  585. +node setup_realm.js
  586. +
  587. +cd "$PROJECT_ROOT"
  588. +
  589. +# --------------- NEXTCLOUD KONFIGURATION ---------------
  590. +echo ">>> Nextcloud Konfiguration..."
  591. +
  592. +# Verify if variable is set from earlier in the script
  593. +echo ">>> Debug: Checking original variable..."
  594. +echo ">>> Debug: KEYCLOAK_NEXTCLOUD_CLIENT_SECRET = ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}"
  595. +
  596. +# Try reading from .env file if variable is empty
  597. +if [ -z "${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}" ]; then
  598. + echo ">>> Debug: Variable is empty, trying to read from .env file..."
  599. + KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(grep KEYCLOAK_NEXTCLOUD_CLIENT_SECRET "${KEYCLOAK_SETUP_DIR}/.env" | cut -d '=' -f2)
  600. + echo ">>> Debug: Value from .env file = ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}"
  601. +fi
  602. +
  603. +# Ensure we have a value
  604. +if [ -z "${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}" ]; then
  605. + echo ">>> Error: Could not get client secret value"
  606. + exit 1
  607. +fi
  608. +
  609. +# Escape special characters in the secret for JSON
  610. +ESCAPED_SECRET=$(echo "$KEYCLOAK_NEXTCLOUD_CLIENT_SECRET" | sed 's/["\]/\\&/g')
  611. +echo ">>> Debug: Escaped secret = $ESCAPED_SECRET"
  612. +
  613. +# Create the extra vars
  614. +EXTRA_VARS="{\"client_secret\": \"$ESCAPED_SECRET\"}"
  615. +echo ">>> Debug: Extra vars = $EXTRA_VARS"
  616. -# Encrypt credentials file
  617. -gpg --symmetric --cipher-algo AES256 "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt"
  618. -rm "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt"
  619. +# Run Ansible with the extra vars
  620. +sudo ansible-playbook \
  621. + -i "$ANSIBLE_INVENTORY" \
  622. + "$ANSIBLE_PLAYBOOK" \
  623. + --extra-vars "$EXTRA_VARS" \
  624. + -v
  625. -echo "Environment setup completed!"
  626. -echo "Credentials have been saved and encrypted in: ${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
  627. -echo ".env file has been created in: ${DOCKER_DIR}/.env"
  628. -echo ""
  629. -echo "To view credentials, use:"
  630. -echo "gpg -d ${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
  631. \ No newline at end of file
  632. +echo ">>> Fertig"
  633. \ No newline at end of file
  634. diff --git a/scripts/setup/keycloak/.env b/scripts/setup/keycloak/.env
  635. index 8c6b3c3..0087b01 100644
  636. --- a/scripts/setup/keycloak/.env
  637. +++ b/scripts/setup/keycloak/.env
  638. @@ -6,4 +6,6 @@ PAPERLESS_CLIENT_ID=paperless
  639. NODERED_CLIENT_ID=nodered
  640. TESTADMIN_PASSWORD=TestAdminPwd
  641. TESTUSER_PASSWORD=TestUserPwd
  642. -KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=D939xgzoxi58T2XZShdUPZP4gsI0kBOu
  643. \ No newline at end of file
  644. +TESTSERVICEUSER_PASSWORD=TestServiceUserPwd
  645. +KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=OSbJ08zyjBWChwBR7S6c1q4sU0d8zvEK
  646. +NEXTCLOUD_URL=https://cloud.mrx8086.com
  647. \ No newline at end of file
  648. diff --git a/scripts/setup/keycloak/setup_realm.js b/scripts/setup/keycloak/setup_realm.js
  649. index 9f67b1e..784d543 100644
  650. --- a/scripts/setup/keycloak/setup_realm.js
  651. +++ b/scripts/setup/keycloak/setup_realm.js
  652. @@ -1,19 +1,26 @@
  653. import dotenv from 'dotenv';
  654. import axios from 'axios';
  655. -// Lade Umgebungsvariablen
  656. +// Load environment variables
  657. dotenv.config();
  658. +console.log('Environment variables loaded.');
  659. -// Konfigurationskonstanten
  660. +// Configuration constants
  661. const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'https://auth.mrx8086.com';
  662. const ADMIN_USERNAME = process.env.KEYCLOAK_ADMIN_USER;
  663. const ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
  664. const REALM_NAME = 'office-automation';
  665. -// Client IDs und deren Konfiguration
  666. +console.log('Configuration constants set:', { KEYCLOAK_URL, ADMIN_USERNAME, REALM_NAME });
  667. +
  668. +// Client IDs and their configuration
  669. const CLIENTS = {
  670. [process.env.NEXTCLOUD_CLIENT_ID || 'nextcloud']: {
  671. - redirectUris: ["https://cloud.mrx8086.com/*"]
  672. + redirectUris: [
  673. + `https://cloud.mrx8086.com/apps/sociallogin/custom_oidc/keycloak`,
  674. + `https://cloud.mrx8086.com/apps/user_oidc/code`
  675. + ],
  676. + postLogoutRedirectUris: ["https://cloud.mrx8086.com/*"]
  677. },
  678. [process.env.PAPERLESS_CLIENT_ID || 'paperless']: {
  679. redirectUris: ["https://docs.mrx8086.com/*"]
  680. @@ -23,16 +30,18 @@ const CLIENTS = {
  681. }
  682. };
  683. -// Hilfsfunktion für API-Fehlerbehandlung
  684. +console.log('CLIENTS configuration:', CLIENTS);
  685. +
  686. +// Helper function for API error handling
  687. const handleAxiosError = (error, operation, config, response) => {
  688. console.error(`Error during ${operation}:`);
  689. if (config) {
  690. - console.error('Request:', {
  691. - method: config.method,
  692. - url: config.url,
  693. - headers: config.headers,
  694. - data: config.data,
  695. - });
  696. + console.error('Request:', {
  697. + method: config.method,
  698. + url: config.url,
  699. + headers: config.headers,
  700. + data: config.data,
  701. + });
  702. }
  703. if (error.response) {
  704. console.error('Response:', {
  705. @@ -45,8 +54,9 @@ const handleAxiosError = (error, operation, config, response) => {
  706. throw error;
  707. };
  708. -// Admin Token abrufen
  709. +// Get Admin Token
  710. async function getAdminToken() {
  711. + console.log('Getting admin token...');
  712. try {
  713. const response = await axios.post(
  714. `${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token`,
  715. @@ -62,165 +72,146 @@ async function getAdminToken() {
  716. }
  717. }
  718. );
  719. + console.log('Admin token received.');
  720. return response.data.access_token;
  721. } catch (error) {
  722. - handleAxiosError(error, 'getting admin token');
  723. + handleAxiosError(error, 'getting admin token');
  724. }
  725. }
  726. -// Prüfen ob Realm existiert
  727. +// Check if Realm exists
  728. async function checkRealmExists(token) {
  729. + console.log(`Checking if realm ${REALM_NAME} exists...`);
  730. try {
  731. - await axios.get(
  732. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}`,
  733. - {
  734. - headers: {
  735. - 'Authorization': `Bearer ${token}`
  736. - }
  737. - }
  738. - );
  739. + await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}`, {
  740. + headers: { 'Authorization': `Bearer ${token}` }
  741. + });
  742. + console.log(`Realm ${REALM_NAME} exists.`);
  743. return true;
  744. } catch (error) {
  745. if (error.response?.status === 404) {
  746. + console.log(`Realm ${REALM_NAME} does not exist.`);
  747. return false;
  748. }
  749. handleAxiosError(error, 'checking realm existence');
  750. }
  751. }
  752. -
  753. -// Funktion um Client Infos abzufragen
  754. -async function getClient(token, clientId) {
  755. +// Function to get client information by clientId
  756. +async function getClientByClientId(token, clientId) {
  757. + console.log(`Getting client information for ${clientId}...`);
  758. try {
  759. - const response = await axios.get(
  760. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`,
  761. - {
  762. - headers: {
  763. - 'Authorization': `Bearer ${token}`
  764. - },
  765. - params: {
  766. - clientId: clientId
  767. - }
  768. - }
  769. - );
  770. + const response = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`, {
  771. + headers: { 'Authorization': `Bearer ${token}` },
  772. + params: { clientId }
  773. + });
  774. if (response.data.length === 0) {
  775. - console.error(`Client ${clientId} not found`);
  776. + console.log(`Client ${clientId} not found`);
  777. return null;
  778. }
  779. -
  780. + console.log(`Client ${clientId} found.`);
  781. return response.data[0];
  782. } catch (error) {
  783. - handleAxiosError(error, `getting client ${clientId}`);
  784. + handleAxiosError(error, `getting client ${clientId}`);
  785. + return null;
  786. }
  787. }
  788. -// Prüfen ob Client existiert
  789. -async function checkClientExists(token, clientId) {
  790. - const client = await getClient(token, clientId);
  791. - return !!client;
  792. -}
  793. -
  794. +// Check if client exists
  795. +const checkClientExists = async (token, clientId) => !!await getClientByClientId(token, clientId);
  796. +// Get client mappers by client ID
  797. async function getClientMappers(token, clientId) {
  798. + console.log(`Getting client mappers for ${clientId}...`);
  799. + const client = await getClientByClientId(token, clientId);
  800. + if (!client) {
  801. + console.log(`Client ${clientId} not found, no mappers to get.`);
  802. + return [];
  803. + }
  804. try {
  805. - const client = await getClient(token, clientId);
  806. - if (!client) {
  807. - return [];
  808. - }
  809. const response = await axios.get(
  810. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
  811. - {
  812. - headers: {
  813. - 'Authorization': `Bearer ${token}`
  814. - }
  815. - }
  816. + { headers: { 'Authorization': `Bearer ${token}` } }
  817. );
  818. + console.log(`Client mappers for ${clientId} retrieved.`);
  819. return response.data;
  820. } catch (error) {
  821. - handleAxiosError(error, `getting client mappers for ${clientId}`, error.config, error.response);
  822. + handleAxiosError(error, `getting client mappers for ${clientId}`, error.config, error.response);
  823. return [];
  824. }
  825. }
  826. -async function getClientScopes(token, clientId){
  827. +// Get client scopes for a client
  828. +async function getClientScopes(token, clientId) {
  829. + console.log(`Getting client scopes for ${clientId}...`);
  830. + const client = await getClientByClientId(token, clientId);
  831. + if (!client) {
  832. + console.log(`Client ${clientId} not found, no client scopes to get.`);
  833. + return [];
  834. + }
  835. try {
  836. - const client = await getClient(token, clientId);
  837. - if(!client)
  838. - return [];
  839. -
  840. const response = await axios.get(
  841. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/client-scopes`,
  842. - {
  843. - headers: {
  844. - 'Authorization': `Bearer ${token}`
  845. - }
  846. - }
  847. + { headers: { 'Authorization': `Bearer ${token}` } }
  848. );
  849. -
  850. + console.log(`Client scopes for ${clientId} retrieved.`);
  851. return response.data;
  852. -
  853. - } catch(error){
  854. - handleAxiosError(error, `getting client scopes for ${clientId}`, error.config, error.response);
  855. + } catch (error) {
  856. + handleAxiosError(error, `getting client scopes for ${clientId}`, error.config, error.response);
  857. return [];
  858. }
  859. }
  860. +// Get a specific client scope by name
  861. async function getClientScope(token, scopeName) {
  862. + console.log(`Getting client scope "${scopeName}"...`);
  863. try {
  864. const response = await axios.get(
  865. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes`,
  866. - {
  867. - headers: {
  868. - 'Authorization': `Bearer ${token}`
  869. - },
  870. - params: {
  871. - name: scopeName
  872. - }
  873. - }
  874. + { headers: { 'Authorization': `Bearer ${token}` } }
  875. );
  876. -
  877. - if(response.data.length === 0){
  878. - console.error(`Client Scope ${scopeName} not found`);
  879. + const foundScope = response.data.find(scope => scope.name === scopeName);
  880. + if (!foundScope) {
  881. + console.log(`Client Scope "${scopeName}" not found`);
  882. return null;
  883. }
  884. -
  885. - return response.data[0]
  886. - } catch (error){
  887. + console.log(`Client scope "${scopeName}" found:`, foundScope);
  888. + return foundScope;
  889. + } catch (error) {
  890. handleAxiosError(error, `getting client scope ${scopeName}`, error.config, error.response);
  891. return null;
  892. }
  893. }
  894. -async function addDefaultClientScope(token, clientId, scopeName){
  895. +// Add a default client scope to a client
  896. +async function addDefaultClientScope(token, clientId, scopeName) {
  897. + console.log(`Adding client scope "${scopeName}" as default for client "${clientId}"...`);
  898. + const client = await getClientByClientId(token, clientId);
  899. + const scope = await getClientScope(token, scopeName);
  900. + if (!client || !scope) {
  901. + console.log(`Client "${clientId}" or scope "${scopeName}" not found, cannot add as default scope.`);
  902. + return;
  903. + }
  904. try {
  905. - const client = await getClient(token, clientId);
  906. - const scope = await getClientScope(token, scopeName);
  907. - if(!client || !scope){
  908. - return null;
  909. - }
  910. -
  911. -
  912. await axios.put(
  913. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/default-client-scopes/${scope.id}`,
  914. - null,
  915. - {
  916. - headers: {
  917. - 'Authorization': `Bearer ${token}`,
  918. - 'Content-Type': 'application/json'
  919. - }
  920. - }
  921. + `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/default-client-scopes/${scope.id}`,
  922. + null,
  923. + {
  924. + headers: {
  925. + 'Authorization': `Bearer ${token}`,
  926. + 'Content-Type': 'application/json'
  927. + }
  928. + }
  929. );
  930. -
  931. - console.log(`Client scope ${scopeName} added as default scope for client ${clientId}`)
  932. -
  933. - } catch(error){
  934. - handleAxiosError(error, `adding client scope ${scopeName} as default for client ${clientId}`);
  935. + console.log(`Client scope "${scopeName}" added as default scope for client "${clientId}"`);
  936. + } catch (error) {
  937. + handleAxiosError(error, `adding client scope "${scopeName}" as default for client "${clientId}"`);
  938. }
  939. }
  940. -
  941. -// Realm erstellen
  942. +// Create Realm
  943. async function createRealm(token) {
  944. + console.log(`Creating realm ${REALM_NAME}...`);
  945. const realmConfig = {
  946. realm: REALM_NAME,
  947. enabled: true,
  948. @@ -250,67 +241,47 @@ async function createRealm(token) {
  949. webAuthnPolicyUserVerificationRequirement: "preferred",
  950. webAuthnPolicyCreateTimeout: 0,
  951. webAuthnPolicyAvoidSameAuthenticatorRegister: false,
  952. - defaultDefaultClientScopes: [
  953. - "email",
  954. - "profile",
  955. - "roles",
  956. - "web-origins"
  957. - ],
  958. - defaultOptionalClientScopes: [
  959. - "address",
  960. - "phone",
  961. - "offline_access",
  962. - "microprofile-jwt"
  963. - ]
  964. + defaultDefaultClientScopes: ["email", "profile", "roles", "web-origins"],
  965. + defaultOptionalClientScopes: ["address", "phone", "offline_access", "microprofile-jwt"]
  966. };
  967. -
  968. try {
  969. - await axios.post(
  970. - `${KEYCLOAK_URL}/admin/realms`,
  971. - realmConfig,
  972. - {
  973. - headers: {
  974. - 'Authorization': `Bearer ${token}`,
  975. - 'Content-Type': 'application/json'
  976. - }
  977. + await axios.post(`${KEYCLOAK_URL}/admin/realms`, realmConfig, {
  978. + headers: {
  979. + 'Authorization': `Bearer ${token}`,
  980. + 'Content-Type': 'application/json'
  981. }
  982. - );
  983. + });
  984. console.log('Realm created successfully');
  985. } catch (error) {
  986. handleAxiosError(error, 'creating realm');
  987. }
  988. }
  989. -// Client erstellen
  990. +// Create client and manage mappers
  991. async function createClient(token, clientId, clientName, redirectUris) {
  992. - let client;
  993. - const clientExists = await checkClientExists(token, clientId);
  994. + console.log(`Creating client "${clientId}"...`);
  995. + let client = await getClientByClientId(token, clientId);
  996. - if (!clientExists) {
  997. + if (!client) {
  998. const clientConfig = {
  999. clientId: clientId,
  1000. name: clientName,
  1001. enabled: true,
  1002. protocol: "openid-connect",
  1003. publicClient: false,
  1004. - authorizationServicesEnabled: true,
  1005. - serviceAccountsEnabled: true,
  1006. + authorizationServicesEnabled: false,
  1007. + serviceAccountsEnabled: false,
  1008. standardFlowEnabled: true,
  1009. implicitFlowEnabled: false,
  1010. directAccessGrantsEnabled: true,
  1011. redirectUris: redirectUris,
  1012. - webOrigins: ["+"],
  1013. - defaultClientScopes: [
  1014. - "roles"
  1015. - ],
  1016. - optionalClientScopes: [
  1017. - "address",
  1018. - "phone",
  1019. - "offline_access",
  1020. - "microprofile-jwt"
  1021. - ]
  1022. + webOrigins: ["+"],
  1023. + defaultClientScopes: ["roles"],
  1024. + optionalClientScopes: ["address", "phone", "offline_access", "microprofile-jwt"],
  1025. + rootUrl: process.env.NEXTCLOUD_URL,
  1026. + baseUrl: process.env.NEXTCLOUD_URL,
  1027. + adminUrl: process.env.NEXTCLOUD_URL,
  1028. };
  1029. -
  1030. try {
  1031. const response = await axios.post(
  1032. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`,
  1033. @@ -322,21 +293,34 @@ async function createClient(token, clientId, clientName, redirectUris) {
  1034. }
  1035. }
  1036. );
  1037. - console.log(`Client ${clientId} created successfully`);
  1038. + console.log(`Client "${clientId}" created successfully`);
  1039. client = response.data;
  1040. } catch (error) {
  1041. handleAxiosError(error, `creating client: ${clientId}`);
  1042. return;
  1043. }
  1044. } else {
  1045. - client = await getClient(token, clientId);
  1046. - console.log(`Client ${clientId} already exists, checking mappers`);
  1047. + console.log(`Client "${clientId}" already exists, checking mappers`);
  1048. }
  1049. - if (client) {
  1050. -
  1051. - const existingMappers = await getClientMappers(token, clientId)
  1052. + if (client) {
  1053. + try {
  1054. + await axios.put(
  1055. + `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}`,
  1056. + { ...client, secret: process.env[`KEYCLOAK_${clientId.replace(/[^a-zA-Z0-9]/g, '').toUpperCase()}_CLIENT_SECRET`] },
  1057. + {
  1058. + headers: {
  1059. + 'Authorization': `Bearer ${token}`,
  1060. + 'Content-Type': 'application/json'
  1061. + }
  1062. + }
  1063. + );
  1064. + console.log(`Set client secret for client: ${clientId}`);
  1065. + } catch (error) {
  1066. + handleAxiosError(error, `setting client secret for client: ${clientId}`, error.config, error.response);
  1067. + }
  1068. + const existingMappers = await getClientMappers(token, clientId);
  1069. const requiredMappers = [
  1070. {
  1071. name: "groups",
  1072. @@ -367,10 +351,8 @@ async function createClient(token, clientId, clientName, redirectUris) {
  1073. for (const mapper of requiredMappers) {
  1074. const existingMapper = existingMappers.find(m => m.name === mapper.name);
  1075. -
  1076. try {
  1077. if (existingMapper) {
  1078. - // Update existierenden Mapper
  1079. await axios.put(
  1080. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models/${existingMapper.id}`,
  1081. { ...existingMapper, ...mapper },
  1082. @@ -381,9 +363,8 @@ async function createClient(token, clientId, clientName, redirectUris) {
  1083. }
  1084. }
  1085. );
  1086. - console.log(`Mapper ${mapper.name} updated for client ${clientId}`);
  1087. + console.log(`Mapper "${mapper.name}" updated for client "${clientId}"`);
  1088. } else {
  1089. - // Erstelle neuen Mapper
  1090. await axios.post(
  1091. `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
  1092. mapper,
  1093. @@ -394,70 +375,69 @@ async function createClient(token, clientId, clientName, redirectUris) {
  1094. }
  1095. }
  1096. );
  1097. - console.log(`Mapper ${mapper.name} created for client ${clientId}`);
  1098. + console.log(`Mapper "${mapper.name}" created for client "${clientId}"`);
  1099. }
  1100. } catch (error) {
  1101. - handleAxiosError(error, `managing mapper ${mapper.name} for client ${clientId}`, error.config, error.response);
  1102. - // Wir werfen den Fehler nicht weiter, damit andere Mapper noch verarbeitet werden können
  1103. + handleAxiosError(error, `managing mapper "${mapper.name}" for client "${clientId}"`, error.config, error.response);
  1104. + }
  1105. + }
  1106. +
  1107. + if (clientId.includes("nextcloud")) {
  1108. + await addDefaultClientScope(token, clientId, "openid");
  1109. + await addDefaultClientScope(token, clientId, "profile");
  1110. + await addDefaultClientScope(token, clientId, "groups-nextcloud");
  1111. +
  1112. + try {
  1113. + await axios.put(
  1114. + `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}`,
  1115. + { ...client, defaultClientScopes: client.defaultClientScopes.filter(c => c !== "nextcloud-dedicated") },
  1116. + {
  1117. + headers: {
  1118. + 'Authorization': `Bearer ${token}`,
  1119. + 'Content-Type': 'application/json'
  1120. + }
  1121. + }
  1122. + );
  1123. + console.log(`Removed client scope nextcloud-dedicated from client: ${clientId}`);
  1124. + } catch (error) {
  1125. + handleAxiosError(error, `removing client scope nextcloud-dedicated from client: ${clientId}`, error.config, error.response);
  1126. }
  1127. }
  1128. }
  1129. }
  1130. -
  1131. -// Gruppen erstellen
  1132. +// Create default groups
  1133. async function createDefaultGroups(token) {
  1134. + console.log('Creating default groups...');
  1135. const groups = [
  1136. - {
  1137. - name: "Administrators",
  1138. - path: "/Administrators",
  1139. - attributes: {
  1140. - "description": ["Full system access"]
  1141. - }
  1142. - },
  1143. - {
  1144. - name: "Users",
  1145. - path: "/Users",
  1146. - attributes: {
  1147. - "description": ["Regular system users"]
  1148. - }
  1149. - }
  1150. + { name: "nextcloud-admins", path: "/nextcloud-admins", attributes: { "description": ["Nextcloud administrators"] } },
  1151. + { name: "nextcloud-users", path: "/nextcloud-users", attributes: { "description": ["Nextcloud regular users"] } },
  1152. + { name: "nextcloud-youpi", path: "/nextcloud-youpi", attributes: { "description": ["Nextcloud youpi"] } },
  1153. + { name: "nextcloud-service", path: "/nextcloud-service", attributes: { "description": ["Nextcloud service user"] } }
  1154. ];
  1155. for (const group of groups) {
  1156. try {
  1157. - // Prüfen ob Gruppe existiert
  1158. - const existingGroup = await axios.get(
  1159. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`,
  1160. - {
  1161. - headers: {
  1162. - 'Authorization': `Bearer ${token}`
  1163. - },
  1164. - params: {
  1165. - search: group.name,
  1166. - }
  1167. - }
  1168. - );
  1169. + const existingGroups = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`, {
  1170. + headers: { 'Authorization': `Bearer ${token}` },
  1171. + params: { search: group.name, exact: true } // Added exact: true for precise matching
  1172. + });
  1173. - if (existingGroup.data.length > 0) {
  1174. - console.log(`Group ${group.name} already exists`);
  1175. + if (existingGroups.data.length > 0) {
  1176. + console.log(`Group "${group.name}" already exists`);
  1177. continue;
  1178. }
  1179. - await axios.post(
  1180. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`,
  1181. - group,
  1182. - {
  1183. - headers: {
  1184. - 'Authorization': `Bearer ${token}`,
  1185. - 'Content-Type': 'application/json'
  1186. - }
  1187. + await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`, group, {
  1188. + headers: {
  1189. + 'Authorization': `Bearer ${token}`,
  1190. + 'Content-Type': 'application/json'
  1191. }
  1192. - );
  1193. - console.log(`Group ${group.name} created successfully`);
  1194. + });
  1195. + console.log(`Group "${group.name}" created successfully`);
  1196. } catch (error) {
  1197. if (error.response?.status === 409) {
  1198. - console.log(`Group ${group.name} already exists`);
  1199. + console.log(`Group "${group.name}" already exists`);
  1200. } else {
  1201. handleAxiosError(error, `creating group: ${group.name}`);
  1202. }
  1203. @@ -465,44 +445,44 @@ async function createDefaultGroups(token) {
  1204. }
  1205. }
  1206. -
  1207. +// Create a test token for a user
  1208. async function createTestToken(token, username) {
  1209. + console.log(`Creating test token for user "${username}"...`);
  1210. try {
  1211. - const nextcloudClientId = Object.keys(CLIENTS).find(key => key.includes('nextcloud')) || 'nextcloud';
  1212. - const client = await getClient(token, nextcloudClientId);
  1213. + const nextcloudClientId = Object.keys(CLIENTS).find(key => key.includes('nextcloud')) || 'nextcloud';
  1214. + const client = await getClientByClientId(token, nextcloudClientId);
  1215. - if (!client)
  1216. + if (!client) {
  1217. + console.log(`Client "${nextcloudClientId}" not found, cannot create test token.`);
  1218. return null;
  1219. + }
  1220. const response = await axios.post(
  1221. `${KEYCLOAK_URL}/realms/${REALM_NAME}/protocol/openid-connect/token`,
  1222. new URLSearchParams({
  1223. 'client_id': nextcloudClientId,
  1224. - 'client_secret': process.env.KEYCLOAK_NEXTCLOUD_CLIENT_SECRET,
  1225. + 'client_secret': process.env[`KEYCLOAK_${nextcloudClientId.replace(/[^a-zA-Z0-9]/g, '').toUpperCase()}_CLIENT_SECRET`],
  1226. 'username': username,
  1227. 'password': process.env.TESTADMIN_PASSWORD || "initial123!",
  1228. 'grant_type': 'password'
  1229. }),
  1230. - {
  1231. - headers: {
  1232. - 'Content-Type': 'application/x-www-form-urlencoded'
  1233. - }
  1234. - }
  1235. + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  1236. );
  1237. + console.log(`Test token for user "${username}" created.`);
  1238. return response.data.access_token;
  1239. } catch (error) {
  1240. handleAxiosError(error, `getting test token for ${username}`, error.config, error.response);
  1241. + return null;
  1242. }
  1243. }
  1244. -// Funktion zum Decodieren eines JWT-Tokens
  1245. +// Function to decode a JWT token
  1246. function decodeToken(token) {
  1247. try {
  1248. const base64Url = token.split('.')[1];
  1249. const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
  1250. - const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
  1251. - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  1252. - }).join(''));
  1253. -
  1254. + const jsonPayload = decodeURIComponent(atob(base64).split('').map(c =>
  1255. + '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
  1256. + ).join(''));
  1257. return JSON.parse(jsonPayload);
  1258. } catch (error) {
  1259. console.error("Error decoding token:", error.message);
  1260. @@ -510,87 +490,128 @@ function decodeToken(token) {
  1261. }
  1262. }
  1263. -// Test-User erstellen
  1264. +// Create initial users
  1265. async function createInitialUsers(token) {
  1266. + console.log('Creating initial users...');
  1267. const users = [
  1268. - {
  1269. - username: "testadmin",
  1270. - enabled: true,
  1271. - emailVerified: true,
  1272. - firstName: "Test",
  1273. - lastName: "Admin",
  1274. - email: "testadmin@mrx8086.com",
  1275. - credentials: [{
  1276. - type: "password",
  1277. - value: process.env.TESTADMIN_PASSWORD || "initial123!",
  1278. - temporary: true
  1279. - }],
  1280. - groups: ["/Administrators"]
  1281. - },
  1282. - {
  1283. - username: "testuser",
  1284. - enabled: true,
  1285. - emailVerified: true,
  1286. - firstName: "Test",
  1287. - lastName: "User",
  1288. - email: "testuser@mrx8086.com",
  1289. - credentials: [{
  1290. - type: "password",
  1291. - value: process.env.TESTUSER_PASSWORD || "initial123!",
  1292. - temporary: true
  1293. - }],
  1294. - groups: ["/Users"]
  1295. - }
  1296. + { username: "testadmin", enabled: true, emailVerified: true, firstName: "Test", lastName: "Admin", email: "testadmin@mrx8086.com", credentials: [{ type: "password", value: process.env.TESTADMIN_PASSWORD || "initial123!", temporary: false }], groups: ["nextcloud-admins", "nextcloud-users"] },
  1297. + { username: "testuser", enabled: true, emailVerified: true, firstName: "Test", lastName: "User", email: "testuser@mrx8086.com", credentials: [{ type: "password", value: process.env.TESTUSER_PASSWORD || "initial123!", temporary: false }], groups: ["nextcloud-users", "nextcloud-youpi"] },
  1298. + { username: "testserviceuser", enabled: true, emailVerified: true, firstName: "Test", lastName: "Service User", email: "testserviceuser@mrx8086.com", credentials: [{ type: "password", value: process.env.TESTSERVICEUSER_PASSWORD || "initial123!", temporary: false }], groups: ["nextcloud-service"] }
  1299. ];
  1300. for (const user of users) {
  1301. try {
  1302. - // Prüfen ob User existiert
  1303. - const existingUsers = await axios.get(
  1304. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users`,
  1305. - {
  1306. - headers: {
  1307. - 'Authorization': `Bearer ${token}`
  1308. - },
  1309. - params: {
  1310. - username: user.username,
  1311. - exact: true
  1312. - }
  1313. - }
  1314. - );
  1315. + const existingUsers = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users`, {
  1316. + headers: { 'Authorization': `Bearer ${token}` },
  1317. + params: { username: user.username, exact: true } // Added exact: true for precise matching
  1318. + });
  1319. if (existingUsers.data.length > 0) {
  1320. - console.log(`User ${user.username} already exists`);
  1321. + console.log(`User "${user.username}" already exists`);
  1322. continue;
  1323. }
  1324. - // User erstellen
  1325. - await axios.post(
  1326. - `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users`,
  1327. - user,
  1328. + await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users`, user, {
  1329. + headers: {
  1330. + 'Authorization': `Bearer ${token}`,
  1331. + 'Content-Type': 'application/json'
  1332. + }
  1333. + });
  1334. + console.log(`User "${user.username}" created successfully`);
  1335. +
  1336. + } catch (error) {
  1337. + handleAxiosError(error, `creating user: ${user.username}`, error.config, error.response);
  1338. + }
  1339. + }
  1340. +}
  1341. +
  1342. +async function createGroupsNextcloudScope(token) {
  1343. + const scopeName = "groups-nextcloud";
  1344. + const mapperName = "groups-mapper";
  1345. + console.log(`Starting createGroupsNextcloudScope`);
  1346. + let clientScope = await getClientScope(token, scopeName);
  1347. +
  1348. + if (!clientScope) {
  1349. + try {
  1350. + console.log(`Creating client scope "${scopeName}"`);
  1351. + clientScope = await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes`,
  1352. + {
  1353. + "name": scopeName,
  1354. + "protocol": "openid-connect",
  1355. + "description": "Provides access to user group information for Nextcloud.", // Hinzugefügt: Beschreibung
  1356. + "attributes": {},
  1357. + "consentScreenText": "Grant access to user groups in Nextcloud",
  1358. + "includeInTokenScope": true
  1359. + },
  1360. {
  1361. headers: {
  1362. 'Authorization': `Bearer ${token}`,
  1363. 'Content-Type': 'application/json'
  1364. }
  1365. - }
  1366. - );
  1367. - console.log(`User ${user.username} created successfully`);
  1368. + });
  1369. + console.log(`Client scope "${scopeName}" created successfully`);
  1370. + clientScope = response.data;
  1371. + } catch (error) {
  1372. + console.error(`Error creating client scope "${scopeName}":`, error);
  1373. + handleAxiosError(error, `creating ${scopeName} client scope`, error.config, error.response);
  1374. + return;
  1375. + }
  1376. + } else {
  1377. + console.log(`Client scope "${scopeName}" exists, skipping creation`);
  1378. + }
  1379. + console.log("Client scope creation step finished");
  1380. + if (clientScope) {
  1381. + console.log(`Check for mapper "${mapperName}" in scope "${scopeName}"`);
  1382. + try {
  1383. + const mappersResponse = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes/${clientScope.id}/protocol-mappers/models`,
  1384. + { headers: { 'Authorization': `Bearer ${token}` } }
  1385. + );
  1386. + if (!mappersResponse.data.find(m => m.name === mapperName)) {
  1387. + try {
  1388. + await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes/${clientScope.id}/protocol-mappers/models`,
  1389. + {
  1390. + "name": mapperName,
  1391. + "protocol": "openid-connect",
  1392. + "protocolMapper": "oidc-group-membership-mapper",
  1393. + "config": {
  1394. + "full.path": "false",
  1395. + "id.token.claim": "false",
  1396. + "access.token.claim": "true",
  1397. + "userinfo.token.claim": "true",
  1398. + "claim.name": "groups",
  1399. + "add.to.introspection": "false"
  1400. + }
  1401. + },
  1402. + {
  1403. + headers: {
  1404. + 'Authorization': `Bearer ${token}`,
  1405. + 'Content-Type': 'application/json'
  1406. + }
  1407. + });
  1408. + console.log(`Mapper "${mapperName}" created for client scope "${scopeName}"`);
  1409. + } catch (error) {
  1410. + console.error(`Error creating mapper "${mapperName}" for scope "${scopeName}":`, error);
  1411. + handleAxiosError(error, `creating mapper for ${scopeName}`, error.config, error.response);
  1412. + }
  1413. + } else {
  1414. + console.log(`Mapper "${mapperName}" exists in client scope "${scopeName}", skipping creation`);
  1415. + }
  1416. } catch (error) {
  1417. - handleAxiosError(error, `creating user: ${user.username}`, error.config, error.response);
  1418. + console.error("Error checking for mappers:", error);
  1419. + handleAxiosError(error, `checking mappers for ${scopeName}`, error.config, error.response);
  1420. }
  1421. }
  1422. + console.log("Finished createGroupsNextcloudScope");
  1423. }
  1424. -
  1425. -// Hauptfunktion
  1426. +// Main function
  1427. async function setupRealm() {
  1428. try {
  1429. console.log('Starting Keycloak setup...');
  1430. const token = await getAdminToken();
  1431. - // Prüfe ob Realm existiert
  1432. + // Check if realm exists
  1433. const realmExists = await checkRealmExists(token);
  1434. if (!realmExists) {
  1435. @@ -600,41 +621,37 @@ async function setupRealm() {
  1436. console.log('Realm already exists, skipping base setup');
  1437. }
  1438. - // Clients erstellen
  1439. + // Create client scope groups-nextcloud
  1440. + await createGroupsNextcloudScope(token);
  1441. +
  1442. + // Create clients
  1443. for (const clientId in CLIENTS) {
  1444. await createClient(token, clientId, clientId, CLIENTS[clientId].redirectUris);
  1445. }
  1446. - const nextcloudClientId = Object.keys(CLIENTS).find(key => key.includes('nextcloud')) || 'nextcloud';
  1447. - await addDefaultClientScope(token, nextcloudClientId, "openid");
  1448. -
  1449. - // Gruppen erstellen
  1450. + // Create groups
  1451. await createDefaultGroups(token);
  1452. - // Test User erstellen
  1453. + // Create test users
  1454. await createInitialUsers(token);
  1455. -
  1456. - // Konfiguration des Office-Automation Realms mit Admin Token auslesen
  1457. + // Read the configuration of the Office-Automation realm with Admin Token
  1458. if (token) {
  1459. console.log("Master Realm Admin Token:", token);
  1460. -
  1461. try {
  1462. const realmConfig = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}`, {
  1463. - headers: {
  1464. - 'Authorization': `Bearer ${token}`
  1465. - }
  1466. + headers: { 'Authorization': `Bearer ${token}` }
  1467. });
  1468. - console.log("Office Automation Realm Configuration:", realmConfig.data)
  1469. + console.log("Office Automation Realm Configuration:", realmConfig.data);
  1470. } catch (error) {
  1471. handleAxiosError(error, 'getting office realm configuration', error.config, error.response);
  1472. }
  1473. } else {
  1474. - console.error("Error getting Master Realm admin token")
  1475. + console.error("Error getting Master Realm admin token");
  1476. }
  1477. - // Test Token erstellen
  1478. - const testToken = await createTestToken(token, "testadmin@mrx8086.com");
  1479. + // Create Test Token
  1480. + const testToken = await createTestToken(token, "testadmin");
  1481. if (testToken) {
  1482. console.log("Test Token generated successfully!");
  1483. @@ -644,7 +661,6 @@ async function setupRealm() {
  1484. } else {
  1485. console.error("Error generating Test Token");
  1486. }
  1487. -
  1488. console.log('Setup completed successfully');
  1489. } catch (error) {
  1490. @@ -653,5 +669,5 @@ async function setupRealm() {
  1491. }
  1492. }
  1493. -// Script ausführen
  1494. +// Execute the script
  1495. setupRealm();
  1496. \ No newline at end of file
  1497. diff --git a/scripts/setup/keycloak/test_realm.js b/scripts/setup/keycloak/test_realm.js
  1498. index 78c03a4..11e3254 100644
  1499. --- a/scripts/setup/keycloak/test_realm.js
  1500. +++ b/scripts/setup/keycloak/test_realm.js
  1501. @@ -6,7 +6,7 @@ dotenv.config();
  1502. const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'https://auth.mrx8086.com';
  1503. const NEXTCLOUD_CLIENT_ID = process.env.NEXTCLOUD_CLIENT_ID || 'nextcloud';
  1504. const TESTADMIN_USERNAME = "testadmin@mrx8086.com";
  1505. -const TESTADMIN_PASSWORD = process.env.TESTADMIN_PASSWORD || "initial123!";
  1506. +const TESTADMIN_PASSWORD = process.env.TESTADMIN_PASSWORD;
  1507. const REALM_NAME = 'office-automation';
  1508. const CLIENT_SECRET = process.env.KEYCLOAK_NEXTCLOUD_CLIENT_SECRET;
  1509. @@ -74,28 +74,33 @@ function decodeToken(token) {
  1510. }
  1511. }
  1512. +// Prüfe ob ein Admin Token korrekt generiert werden kann
  1513. async function testKeycloakLogin() {
  1514. - try {
  1515. - const accessToken = await getAccessToken(TESTADMIN_USERNAME, TESTADMIN_PASSWORD);
  1516. + try {
  1517. + const accessToken = await getAccessToken(TESTADMIN_USERNAME, TESTADMIN_PASSWORD);
  1518. - if (!accessToken) {
  1519. - console.error('Failed to get access token.');
  1520. - return;
  1521. - }
  1522. - console.log('Access Token:', accessToken);
  1523. - const decodedToken = decodeToken(accessToken);
  1524. - if (decodedToken) {
  1525. - console.log('Decoded Access Token:', decodedToken);
  1526. - if (decodedToken.groups.includes('/Administrators')){
  1527. - console.log("Admin Group is set correctly!")
  1528. - } else {
  1529. - console.error("Admin Group is not set correctly!")
  1530. - }
  1531. - }
  1532. + if (!accessToken) {
  1533. + console.error('Failed to get access token.');
  1534. + return;
  1535. + }
  1536. + console.log('Access Token:', accessToken);
  1537. + const decodedToken = decodeToken(accessToken);
  1538. + if(decodedToken) {
  1539. + console.log('Decoded Access Token:', decodedToken);
  1540. + if (Array.isArray(decodedToken.groups) && decodedToken.groups.includes('/nextcloud-admins')){
  1541. + console.log("Admin Group is set correctly!")
  1542. + } else if (typeof decodedToken.groups === 'string' && decodedToken.groups.includes('/nextcloud-admins')) {
  1543. + console.log("Admin Group is set correctly!")
  1544. + }
  1545. + else {
  1546. + console.error("Admin Group is not set correctly!")
  1547. + }
  1548. + }
  1549. - } catch (error) {
  1550. - console.error('An error occurred:', error);
  1551. - }
  1552. +
  1553. + } catch (error) {
  1554. + console.error('An error occurred:', error);
  1555. + }
  1556. }
  1557. testKeycloakLogin();
  1558. \ No newline at end of file