@continuoussecuritytooling/keycloak-reporter 0.7.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -1,2 +1,3 @@
1
1
  # These are supported funding model platforms
2
- open_collective: m13t
2
+ open_collective: m13t
3
+ github: ContinuousSecurityTooling
@@ -18,6 +18,7 @@ jobs:
18
18
  node_version:
19
19
  - 18
20
20
  - 20
21
+ - 21
21
22
  os:
22
23
  - ubuntu-latest
23
24
  - macOS-latest
@@ -49,18 +50,18 @@ jobs:
49
50
  with:
50
51
  version: v3.11.2
51
52
 
52
- - uses: actions/setup-python@v4
53
+ - uses: actions/setup-python@v5
53
54
  with:
54
55
  python-version: '3.9'
55
56
  check-latest: true
56
57
 
57
58
  - name: Helm Chart Testing
58
- uses: helm/chart-testing-action@v2.6.0
59
+ uses: helm/chart-testing-action@v2.6.1
59
60
 
60
61
  - name: Run chart-testing (list-changed)
61
62
  id: list-changed
62
63
  run: |
63
- changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }})
64
+ changed=$(ct list-changed --target-branch main)
64
65
  if [[ -n "$changed" ]]; then
65
66
  echo "changed=true" >> "$GITHUB_OUTPUT"
66
67
  fi
@@ -73,11 +74,15 @@ jobs:
73
74
  if: steps.list-changed.outputs.changed == 'true'
74
75
  uses: helm/kind-action@v1.8.0
75
76
 
76
- - name: Run chart-testing (install)
77
+ - name: Run chart-testing (install - no further args)
77
78
  if: steps.list-changed.outputs.changed == 'true'
78
- run: ct install --target-branch ${{ github.event.repository.default_branch }} --helm-extra-set-args "--set 'keycloak.config.url=http://localhost:8080' --set 'keycloak.config.url=http://localhost:8080' --set 'keycloak.config.clientId=clientId' --set 'keycloak.config.clientSecret=clientSecret' --set 'keycloak.config.webhookType=test' --set 'keycloak.config.webhookUrl=http://localhost:8888'"
79
+ run: ct install --target-branch ${{ github.event.repository.default_branch }} --helm-extra-set-args "--set 'keycloak.config.url=http://localhost:8080' --set 'keycloak.config.url=http://localhost:8080' --set 'keycloak.config.clientId=clientId' --set 'keycloak.config.clientSecret=clientSecret'"
79
80
 
80
- - uses: actions/upload-artifact@v3
81
+ - name: Run chart-testing (install - with args)
82
+ if: steps.list-changed.outputs.changed == 'true'
83
+ run: ct install --target-branch ${{ github.event.repository.default_branch }} --helm-extra-set-args "-f charts/keycloak-reporter/ci.values.yaml"
84
+
85
+ - uses: actions/upload-artifact@v4
81
86
  with:
82
87
  name: dist-folder
83
88
  path: dist
@@ -89,6 +94,8 @@ jobs:
89
94
  matrix:
90
95
  node_version:
91
96
  - 18
97
+ - 20
98
+ - 21
92
99
  os:
93
100
  - ubuntu-latest
94
101
  steps:
@@ -98,7 +105,7 @@ jobs:
98
105
  with:
99
106
  node-version: '${{ matrix.node_version }}'
100
107
  - name: Install Java
101
- uses: actions/setup-java@v3
108
+ uses: actions/setup-java@v4
102
109
  with:
103
110
  distribution: 'temurin' # See 'Supported distributions' for available options
104
111
  java-version: '17'
@@ -125,7 +132,7 @@ jobs:
125
132
  WEBHOOK_ADDITIONAL_MESSAGE: ${{ github.head_ref || github.ref_name }}
126
133
 
127
134
  package:
128
- name: Build Container Image
135
+ name: Package Application
129
136
  runs-on: ubuntu-latest
130
137
  needs:
131
138
  - build
@@ -136,7 +143,7 @@ jobs:
136
143
  - uses: actions/setup-node@v4
137
144
  with:
138
145
  # renovate: datasource=docker depName=node
139
- node-version: '18'
146
+ node-version: '20'
140
147
  - name: 'Build Package'
141
148
  run: |
142
149
  npm run clean
@@ -145,10 +152,11 @@ jobs:
145
152
  - name: Write version vars
146
153
  run: |
147
154
  BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"`
148
- VERSION=${GITHUB_REF_NAME#v}
149
- echo Version: $VERSION
150
- echo "VERSION=$VERSION" >> $GITHUB_ENV
151
- echo "APP_VERSION=$VERSION" >> $GITHUB_ENV
155
+ BRANCH=${GITHUB_REF_NAME#v}
156
+ APP_VERSION=$(cat package.json | grep version| head -1 | awk -F: '{ print $2 }' | sed 's/[",]//g')
157
+ echo Version: $APP_VERSION
158
+ echo "VERSION=$APP_VERSION" >> $GITHUB_ENV
159
+ echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV
152
160
  echo "BUILD_DATE=$BUILD_DATE" >> $GITHUB_ENV
153
161
 
154
162
  - name: Build Container Image
@@ -156,19 +164,28 @@ jobs:
156
164
  uses: redhat-actions/buildah-build@v2
157
165
  with:
158
166
  image: continuoussecuritytooling/keycloak-reporting-cli
159
- tags: 'rc_build ${{ github.sha }}'
167
+ tags: 'latest next ${{env.APP_VERSION}} ${{env.APP_VERSION}}_rc'
160
168
  containerfiles: |
161
169
  ./Dockerfile
162
170
  build-args: |
163
171
  BUILD_DATE=${{env.BUILD_DATE}}
164
172
  APP_VERSION=${{env.APP_VERSION}}
165
173
 
174
+ - name: Push To NPM Registry
175
+ id: push-to-npm-tagged
176
+ env:
177
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
178
+ run: |
179
+ echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc
180
+ npm publish
181
+ if: github.ref_type == 'tag' || github.tag != ''
182
+
166
183
  - name: Push To Docker Hub
167
184
  id: push-to-dockerhub-preview
168
185
  uses: redhat-actions/push-to-registry@v2
169
186
  with:
170
187
  image: ${{ steps.build-image.outputs.image }}
171
- tags: ${{ steps.build-image.outputs.tags }}
188
+ tags: 'next ${{env.APP_VERSION}}_rc'
172
189
  registry: registry.hub.docker.com
173
190
  username: continuoussecuritytooling
174
191
  password: ${{ secrets.DOCKER_HUB_TOKEN }}
@@ -179,8 +196,8 @@ jobs:
179
196
  uses: redhat-actions/push-to-registry@v2
180
197
  with:
181
198
  image: ${{ steps.build-image.outputs.image }}
182
- tags: latest ${VERSION}
199
+ tags: 'latest ${{env.APP_VERSION}}'
183
200
  registry: registry.hub.docker.com
184
201
  username: continuoussecuritytooling
185
202
  password: ${{ secrets.DOCKER_HUB_TOKEN }}
186
- if: github.ref_type == 'tag'
203
+ if: github.ref_type == 'tag' || github.tag != ''
@@ -26,22 +26,21 @@ jobs:
26
26
  - name: Install Helm
27
27
  uses: azure/setup-helm@v3
28
28
  - name: Install Python
29
- uses: actions/setup-python@v4
29
+ uses: actions/setup-python@v5
30
30
  with:
31
31
  python-version: '3.9'
32
32
  check-latest: true
33
33
  - name: Set up chart-testing
34
- uses: helm/chart-testing-action@v2.6.0
34
+ uses: helm/chart-testing-action@v2.6.1
35
35
 
36
36
  - name: Run chart-testing (lint)
37
- run: ct lint --config .ct.yaml
37
+ run: ct lint --config .ct.yaml
38
38
 
39
39
  - name: Run chart-releaser
40
- uses: helm/chart-releaser-action@v1.5.0
41
- with:
42
- charts_dir: charts/
40
+ uses: helm/chart-releaser-action@v1.6.0
43
41
  env:
44
42
  CR_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
43
+ CR_GENERATE_RELEASE_NOTES: true
45
44
 
46
45
  - name: Login to GitHub Container Registry
47
46
  run: |
@@ -49,6 +48,7 @@ jobs:
49
48
 
50
49
  - name: Push Charts to GHCR
51
50
  run: |
51
+ shopt -s nullglob
52
52
  for pkg in .cr-release-packages/*; do
53
53
  if [ -z "${pkg:-}" ]; then
54
54
  break
package/CHANGELOG.md CHANGED
@@ -1,22 +1,115 @@
1
- # 0.2.0 (2023-06-02)
1
+ ## [0.8.1](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/v0.8.0...v0.8.1) (2023-12-15)
2
2
 
3
3
 
4
4
  ### Bug Fixes
5
5
 
6
- * **deps:** update dependency @json2csv/node to v7 ([42934da](https://github.com/ContinuousSecurityTooling/[object Object]/commit/42934da57a546b1a0db324183b3db51c27ff1cc2))
7
- * **deps:** update dependency @json2csv/node to v7.0.1 ([b0aeb36](https://github.com/ContinuousSecurityTooling/[object Object]/commit/b0aeb366b07a38d8b648b4a0c763bab578db653a))
8
- * Stick to NodeJS 16 ([595d799](https://github.com/ContinuousSecurityTooling/[object Object]/commit/595d799510e81de885430d7cc62549dd8a272aee))
6
+ * **Config:** Allow env overwrites ([37e07b7](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/37e07b71595b9f52509e207c3ccb9e6d526b6320))
7
+ * **Helm:** Correcting invalid indent ([80f4859](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/80f485946384aedaa6bfce25178f928b3fb1b96a))
8
+
9
+
10
+
11
+ # [0.8.0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/v0.7.2...v0.8.0) (2023-12-14)
12
+
13
+ ### Features
14
+
15
+ * **Config:** Adding config validation and helm test hook ([c29e945](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/c29e945567b4dfcdc9a10e710efa2b1a8c00f970))
16
+
17
+ ### Bug Fixes
18
+
19
+ * **deps:** update dependency @continuoussecuritytooling/keycloak-auditor to v1.1.2 ([2b985d5](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/2b985d5daa4d271bf4a1219b6df71b16515b4106))
20
+ * **deps:** update dependency @continuoussecuritytooling/keycloak-auditor to v1.1.3 ([2ed9c0f](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/2ed9c0faff14bc7d43b5e739a48e7175c1e74c4c))
21
+ * **deps:** update dependency @json2csv/node to v7.0.4 ([2488240](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/2488240525fd1d8c20cf5205be50c069e6ac0cd1))
22
+ * **deps:** update dependency @keycloak/keycloak-admin-client to v23 ([12e4485](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/12e4485a0e4c508cc90fe86d3ab39efb647486ce))
23
+ * **deps:** update dependency @keycloak/keycloak-admin-client to v23.0.1 ([babdf78](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/babdf78ce6b0f2736ce6703cb83338e37066639b))
24
+ * **deps:** update dependency npm to v10.2.4 ([8529acf](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/8529acf82bf8ea1581c7510783087ba5d8d45dde))
25
+ * **deps:** update dependency npm to v10.2.5 ([52a3c8b](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/52a3c8b48cbf0ee0d795aa00a9af36291025ae05))
26
+
27
+
28
+ ## [0.7.2](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/v0.7.1...v0.7.2) (2023-11-16)
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * Try to fix release ([ed7ebdf](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/ed7ebdf6ca9677621d19d8f829f611183602135f))
34
+
35
+
36
+
37
+ ## [0.7.1](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/v0.7.0...v0.7.1) (2023-11-16)
38
+
39
+
40
+ ### Bug Fixes
41
+
42
+ * **deps:** update dependency @continuoussecuritytooling/keycloak-auditor to v1.1.1 ([4fb7c58](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/4fb7c5801f8d5519d6c7132eabd29976e640cff3))
43
+ * **deps:** update dependency @slack/webhook to v7.0.1 ([1c46ccf](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1c46ccf7f9a91c4fc85464ddfe9aea8f8e588801))
44
+ * **deps:** update dependency npm to v10.2.3 ([a42ac5c](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/a42ac5c5df195d5e9b15595bb377261f53acca03))
45
+
46
+
47
+ ### Features
48
+
49
+ * Using NodeJS 20 as default ([ba468cf](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/ba468cfa7e17615a38ea5ea7e81c859e1f734f67))
50
+
51
+
52
+
53
+ # [0.7.0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/v0.6.0...v0.7.0) (2023-11-02)
54
+
55
+
56
+
57
+ # [0.6.0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/compare/4c13fa0642d75b8e229091aca052a83fa8c7eb32...v0.6.0) (2023-11-01)
58
+
59
+
60
+ ### Bug Fixes
61
+
62
+ * **Build:** ci health workflow network fix and setup JDK ([9878cac](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/9878cacd99b8c7a66c9c2f7e26d9087f48b809fe))
63
+ * **Chart:** Add only non-empty strings to secret ([eef4332](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/eef433203f33a14a322ecb0a46cd2701ef454eec))
64
+ * **Chart:** Correct default values for install ([50e9b5c](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/50e9b5ccbaeec2661b16cf2d6d959fc66231f21e))
65
+ * **Config:** Adding proper error handling for missing webhook URL ([1515b3d](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1515b3dde0ec387ec226f8d5fe1ffd4f3a4af00d))
66
+ * **Config:** Correcting handling for auditor endpoint toogle ([d332e13](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/d332e13667e5ff770e2d5dcb1374730dcc896527))
67
+ * **Config:** Let config file overwrite defaults ([2df34a0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/2df34a047ef8c2275f8ae4ef0d06209c1619d74e))
68
+ * Correct ref error ([2098b15](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/2098b1531e20d2037252f706713e4dd54a620128))
69
+ * Corrected missing variable ([3223ea3](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/3223ea31d33cad3ad7fd8d4b574ed88a737ced81))
70
+ * Corrected renovate config ([af1bd4a](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/af1bd4a6c4c8678d4a4b2ffc97c41b583986f513))
71
+ * **deps:** update dependency @json2csv/node to v7 ([42934da](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/42934da57a546b1a0db324183b3db51c27ff1cc2))
72
+ * **deps:** update dependency @json2csv/node to v7.0.1 ([b0aeb36](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/b0aeb366b07a38d8b648b4a0c763bab578db653a))
73
+ * **deps:** update dependency @json2csv/node to v7.0.2 ([bcca826](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/bcca8267291c79e13dc1bd563d80d59d1d6d0f27))
74
+ * **deps:** update dependency @json2csv/node to v7.0.3 ([e61eaf2](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/e61eaf2b12243cc10903ac6235e03de78e6c4ae7))
75
+ * **deps:** update dependency @keycloak/keycloak-admin-client to v22 ([cf5caac](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/cf5caac67d0a35b56e7c7a16dd5ee815aaf96d6c))
76
+ * **deps:** update dependency @keycloak/keycloak-admin-client to v22.0.4 ([608703c](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/608703ce5f7d6c05c76eb88296c19e34eee20137))
77
+ * **deps:** update dependency @keycloak/keycloak-admin-client to v22.0.5 ([e56d8ad](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/e56d8ada3b1b7e3ce0a456190f1d4a549309480c))
78
+ * **deps:** update dependency @slack/webhook to v7 ([87872b5](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/87872b5bf56877ace56b49e9b70ace6fd90778a2))
79
+ * **deps:** update dependency npm to v10 ([ff38e4f](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/ff38e4faa13b34d7794b9b36f46d11d61fdc90bf))
80
+ * **deps:** update dependency npm to v10.1.0 ([48bf21a](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/48bf21ae8c251993295901f75150580f3b2a9988))
81
+ * **deps:** update dependency npm to v10.2.0 ([203c3f0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/203c3f03a25838e52dea15eefd564490ba137c2f))
82
+ * **deps:** update dependency npm to v10.2.1 ([1544ee5](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1544ee58ce2cd0e6f1951d45ce77a4cbaf2b0fac))
83
+ * **deps:** update dependency npm to v9.7.1 ([1eeaf8f](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1eeaf8fc51a643da62d46e0669751f732069ee3d))
84
+ * **deps:** update dependency openid-client to v5.4.3 ([6cc9fba](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/6cc9fba92585393bb50cc586a8a7f994b8a6431c))
85
+ * **deps:** update dependency openid-client to v5.5.0 ([efebce8](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/efebce81d16b95e9407bff874a62c5832bdc826e))
86
+ * **deps:** update dependency openid-client to v5.6.0 ([b9020b8](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/b9020b82786a5f5ead45262b756c09a58ff4eb3a))
87
+ * **deps:** update dependency openid-client to v5.6.1 ([ce75f52](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/ce75f527b58f3b3e0de240a0933f3bec79ddd7e1))
88
+ * **deps:** update dependency ramda to v0.29.1 ([015da4c](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/015da4c065810d4aeb3d19b3fbc55633f39ba6af))
89
+ * Fix chart deploy ([0f95f78](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/0f95f78cfcb98cac3da5b8c2bdf84c7bca324d57))
90
+ * **Kubernetes:** Adjust helm chart config error ([f074b0e](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/f074b0eca275e8ee07e0dad6096cd64962dcae80))
91
+ * Stick to NodeJS 16 ([595d799](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/595d799510e81de885430d7cc62549dd8a272aee))
92
+ * **Webhooks:** Corrected error handling ([afe2c60](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/afe2c601852ef5564fcaafe6b959475a4271a9ec))
93
+ * **Webhooks:** Correcting webhook additional message handling and improve error handling ([1fe6fdf](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1fe6fdf3d93dd746c55ea3009a8414cfe3206d2f))
9
94
 
10
95
 
11
96
  ### Features
12
97
 
13
- * **Config:** Provide config file functionality ([f9097f9](https://github.com/ContinuousSecurityTooling/[object Object]/commit/f9097f966c2dfc5240111e9294742ad3821c36ad))
14
- * **Config:** Use config file in helm chart ([21e0512](https://github.com/ContinuousSecurityTooling/[object Object]/commit/21e051243df1a3000d2b57f6ee0feab5f6314910))
15
- * **Helm:** Initial chart version ([401c740](https://github.com/ContinuousSecurityTooling/[object Object]/commit/401c7401b1b34b479bb5a370c9d1077a36f653b0)), closes [#1](https://github.com/ContinuousSecurityTooling/[object Object]/issues/1)
16
- * **Report:** Adding id to report ([8dbc3d4](https://github.com/ContinuousSecurityTooling/[object Object]/commit/8dbc3d4deacba0a5e1729da93b8d933557ebd45b))
17
- * **Testing:** Adding end2end testing via keycloak local ([036202f](https://github.com/ContinuousSecurityTooling/[object Object]/commit/036202f47324e8b3e40764fdc3a43a270a2687cf))
18
- * **Users:** Adding user and client listing functionality ([4c13fa0](https://github.com/ContinuousSecurityTooling/[object Object]/commit/4c13fa0642d75b8e229091aca052a83fa8c7eb32))
19
- * **Webhooks:** Adding Support for Teams and Slack ([66da168](https://github.com/ContinuousSecurityTooling/[object Object]/commit/66da168d2cd234ebc6dd961cfe62a3c8191c0ccc)), closes [#2](https://github.com/ContinuousSecurityTooling/[object Object]/issues/2)
98
+ * Adding report directory support for archiving ([9347ef1](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/9347ef116b8d753b21e66826792865971ce7571d))
99
+ * Allow chart to pass env vars ([37b19b4](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/37b19b428a07c373f308aee529a1ff376b87156e))
100
+ * **API:** Use audit endpoint ([8ed489a](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/8ed489ae0c3e6b66f8506a6d6b87147e50b9a06c))
101
+ * **Config:** Provide config file functionality ([f9097f9](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/f9097f966c2dfc5240111e9294742ad3821c36ad))
102
+ * **Config:** Use config file in helm chart ([21e0512](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/21e051243df1a3000d2b57f6ee0feab5f6314910))
103
+ * **Helm:** Adding OCI helm chart support ([4b3d433](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/4b3d433e2b94550541b821172c7d270abf2363fa))
104
+ * **Helm:** Initial chart version ([401c740](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/401c7401b1b34b479bb5a370c9d1077a36f653b0)), closes [#1](https://github.com/ContinuousSecurityTooling/keycloak-reporter/issues/1)
105
+ * **OCI:** Use OCI standard labels for container image ([3371f13](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/3371f136f51fa0482c253602b281ed508473ed44))
106
+ * **Report:** Adding id to report ([8dbc3d4](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/8dbc3d4deacba0a5e1729da93b8d933557ebd45b))
107
+ * **Security:** apt-upgrade in docker image ([3ac8217](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/3ac82179fcdcec5ff72179e1f33f5e0e9c50c45f))
108
+ * **Security:** Hardening deployment with security config ([3d9fdec](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/3d9fdec7174bc5287b7c382d4aec8207051d3a11))
109
+ * **Testing:** Adding end2end testing via keycloak local ([036202f](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/036202f47324e8b3e40764fdc3a43a270a2687cf))
110
+ * **Users:** Adding user and client listing functionality ([4c13fa0](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/4c13fa0642d75b8e229091aca052a83fa8c7eb32))
111
+ * **Webhook:** Allow custom text for message ([1707e24](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/1707e249c1c9c4c22b1510c767470a2670a4b33b))
112
+ * **Webhooks:** Adding Support for Teams and Slack ([66da168](https://github.com/ContinuousSecurityTooling/keycloak-reporter/commit/66da168d2cd234ebc6dd961cfe62a3c8191c0ccc)), closes [#2](https://github.com/ContinuousSecurityTooling/keycloak-reporter/issues/2)
20
113
 
21
114
 
22
115
 
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:18
1
+ FROM node:20
2
2
 
3
3
  ARG BUILD_DATE
4
4
  ARG APP_VERSION
package/README.md CHANGED
@@ -65,6 +65,9 @@ To install the Helm Chart use the [OCI Package Registry](https://github.com/orgs
65
65
  helm install keycloak-reporter oci://ghcr.io/cloudtooling/helm-charts
66
66
  ```
67
67
 
68
+ >**NOTE**
69
+ >Keep in mind, that you need a client/service account in keycloak with the appropriate rights. You can use this [template](.docs/realm-config.json) to deploy with [keycloak-config-cli](https://github.com/adorsys/keycloak-config-cli) a service account.
70
+
68
71
  ### Config file
69
72
 
70
73
  You can also provider a config file via env var `CONFIG_FILE` and then just provide the commands, e.g.:
@@ -86,4 +89,4 @@ And for Teams:
86
89
  kc-reporter listUsers <Keycloak_Root_URL> <Client_ID> <Client_Secret> --format=json --output=webhook --webhookType=teams --webhookUrl=$WEBHOOK_TESTING_TEAMS
87
90
  ```
88
91
  the following entry in slack will be created:
89
- ![Team Sample](.docs/webhook-teams-sample.png)
92
+ ![Team Sample](.docs/webhook-teams-sample.png)
@@ -15,14 +15,14 @@ type: application
15
15
  # This is the chart version. This version number should be incremented each time you make changes
16
16
  # to the chart and its templates, including the app version.
17
17
  # Versions are expected to follow Semantic Versioning (https://semver.org/)
18
- version: 1.1.0
18
+ version: 1.2.3
19
19
 
20
20
  # This is the version number of the application being deployed. This version number should be
21
21
  # incremented each time you make changes to the application. Versions are not expected to
22
22
  # follow Semantic Versioning. They should reflect the version the application is using.
23
23
  # It is recommended to use it with quotes.
24
- # renovate: datasource=github-tags depName=ContinuousSecurityTooling/keycloak-reporter
25
- appVersion: '0.6.0'
24
+ # renovate: datasource=docker depName=ContinuousSecurityTooling/keycloak-reporter
25
+ appVersion: '0.8.2'
26
26
  maintainers:
27
27
  # Martin Reinhardt
28
28
  - name: hypery2k
@@ -1,6 +1,6 @@
1
1
  # keycloak-reporter
2
2
 
3
- ![Version: 1.1.0](https://img.shields.io/badge/Version-1.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.6.0](https://img.shields.io/badge/AppVersion-0.6.0-informational?style=flat-square)
3
+ ![Version: 1.2.3](https://img.shields.io/badge/Version-1.2.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.8.2](https://img.shields.io/badge/AppVersion-0.8.2-informational?style=flat-square)
4
4
 
5
5
  Keycloak user and client reporting tool for automated regular access checks.
6
6
 
@@ -0,0 +1,13 @@
1
+ env:
2
+ - name: CLIENT_ID
3
+ value: "clientId"
4
+ - name: CLIENT_SECRET
5
+ valueFrom:
6
+ secretKeyRef:
7
+ key: clientSecret
8
+ name: kc-reporter
9
+ keycloak:
10
+ config:
11
+ url: http://localhost:8080
12
+ webhookType: test
13
+ webhookUrl: http://localhost:8888
@@ -18,7 +18,6 @@ spec:
18
18
  imagePullSecrets:
19
19
  {{- toYaml . | nindent 12 }}
20
20
  {{- end }}
21
- # automountServiceAccountToken: false # fix KubernetesClustersShouldDisableAutomountingAPICredentialsMonitoringEffect OPA policy
22
21
  serviceAccountName: {{ default "default" ($.Values.serviceAccount).name }}
23
22
  securityContext:
24
23
  {{- toYaml $.Values.podSecurityContext | nindent 12 }}
@@ -28,14 +27,14 @@ spec:
28
27
  imagePullPolicy: {{ $.Values.image.pullPolicy }}
29
28
  command:
30
29
  - node
31
- - /app/cli.js
30
+ - /app/cli.js
32
31
  - {{ $config.script }}
33
32
  env:
34
33
  - name: CONFIG_FILE
35
34
  value: "/app/config.json"
36
- {{- with $.Values.env }}
37
- {{- tpl (toYaml .) $ | nindent 12 }}
38
- {{- end }}
35
+ {{- with $.Values.env }}
36
+ {{- tpl (toYaml .) $ | nindent 16 }}
37
+ {{- end }}
39
38
  {{- if $.Values.resources }}
40
39
  resources:
41
40
  {{- toYaml $.Values.resources | nindent 16 }}
@@ -0,0 +1,57 @@
1
+ {{- $fullName := include "keycloak-reporter.fullname" . }}
2
+ apiVersion: v1
3
+ kind: Pod
4
+ metadata:
5
+ name: {{ printf "%s-test-connection" $fullName }}
6
+ annotations:
7
+ helm.sh/hook: test
8
+ helm.sh/hook-delete-policy: "hook-succeeded,before-hook-creation"
9
+ helm.sh/hook-weight: "5"
10
+ spec:
11
+ containers:
12
+ - name: config-test
13
+ image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag | default $.Chart.AppVersion }}"
14
+ imagePullPolicy: {{ $.Values.image.pullPolicy }}
15
+ command:
16
+ - node
17
+ - /app/cli.js
18
+ - configTest
19
+ env:
20
+ - name: CONFIG_FILE
21
+ value: "/app/config.json"
22
+ {{- with $.Values.env }}
23
+ {{- tpl (toYaml .) $ | nindent 8 }}
24
+ {{- end }}
25
+ {{- if $.Values.resources }}
26
+ resources:
27
+ {{- toYaml $.Values.resources | nindent 10 }}
28
+ {{- end }}
29
+ securityContext:
30
+ {{- toYaml $.Values.securityContext | nindent 10 }}
31
+ volumeMounts:
32
+ - name: config-file
33
+ mountPath: "/app/config.json"
34
+ subPath: "config.json"
35
+ readOnly: true
36
+ {{- if ($.Values.keycloak.config.volumes).reports }}
37
+ - name: reports-dir
38
+ mountPath: "/app/reports"
39
+ {{- end }}
40
+ {{- if $.Values.nodeSelector }}
41
+ nodeSelector:
42
+ {{ toYaml $.Values.nodeSelector | nindent 4 }}
43
+ {{- end }}
44
+ {{- if $.Values.tolerations }}
45
+ tolerations:
46
+ {{ toYaml $.Values.tolerations | nindent 4 }}
47
+ {{- end }}
48
+ volumes:
49
+ - name: config-file
50
+ secret:
51
+ secretName: {{ $fullName }}
52
+ {{- if ($.Values.keycloak.config.volumes).reports }}
53
+ - name: reports-dir
54
+ persistentVolumeClaim:
55
+ claimName: {{ $fullName }}-reports
56
+ {{- end }}
57
+ restartPolicy: Never
package/cli.ts CHANGED
@@ -4,7 +4,7 @@ import { writeFileSync } from 'node:fs';
4
4
  import path from 'path';
5
5
  import yargs from 'yargs/yargs';
6
6
  import { hideBin } from 'yargs/helpers';
7
- import { listUsers, listClients, Options, convertJSON2CSV, post2Webhook } from './index.js';
7
+ import { configTest, listUsers, listClients, Options, convertJSON2CSV, post2Webhook } from './index.js';
8
8
  import config from './src/config.js';
9
9
  class WebhookConfig {
10
10
  type: string;
@@ -102,6 +102,7 @@ async function convert(format: string, output: string, reports: ReportConfig, co
102
102
  }
103
103
 
104
104
  yargs(hideBin(process.argv))
105
+ .env()
105
106
  .command(
106
107
  'listUsers [url] [clientId] [clientSecret]',
107
108
  'fetches all users in the realms.',
@@ -161,4 +162,11 @@ yargs(hideBin(process.argv))
161
162
  default: false,
162
163
  description: 'use auditior rest endpoint',
163
164
  })
165
+ .command(
166
+ 'configTest [url] [clientId] [clientSecret]',
167
+ 'validates keycloak configuration by reading data via REST API',
168
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
169
+ () => {},
170
+ async (argv) => configTest(getKeycloakConfig(config, argv)),
171
+ )
164
172
  .parse();
package/dist/cli.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ import { writeFileSync } from 'node:fs';
3
+ import path from 'path';
4
+ import yargs from 'yargs/yargs';
5
+ import { hideBin } from 'yargs/helpers';
6
+ import { configTest, listUsers, listClients, convertJSON2CSV, post2Webhook } from './index.js';
7
+ import config from './src/config.js';
8
+ class WebhookConfig {
9
+ constructor(type, url, title, message) {
10
+ this.type = type;
11
+ this.url = url;
12
+ this.title = title;
13
+ this.message = message;
14
+ }
15
+ }
16
+ class ReportConfig {
17
+ }
18
+ function getKeycloakConfig(config, argv) {
19
+ return {
20
+ clientId: config.clientId ? config.clientId : argv.clientId,
21
+ clientSecret: config.clientSecret ? config.clientSecret : argv.clientSecret,
22
+ rootUrl: config.url ? config.url : argv.url,
23
+ useAuditingEndpoint: argv.useAuditingEndpoint == true || config.useAuditingEndpoint.toLowerCase() == 'true',
24
+ };
25
+ }
26
+ function convertData(config, argv, name, title, json) {
27
+ convert(config.format ? config.format : argv.format, config.output ? config.output : argv.output, {
28
+ name,
29
+ directory: argv.reports ? argv.reports : config.reports,
30
+ }, new WebhookConfig(config.webhookType ? config.webhookType : argv.webhookType, config.webhookUrl ? config.webhookUrl : argv.webhookUrl, title, config.webhookMessage ? config.webhookMessage : argv.webhookMessage), json);
31
+ }
32
+ async function convert(format, output, reports, config, json) {
33
+ let outputContent;
34
+ switch (format) {
35
+ case 'csv':
36
+ outputContent = (await convertJSON2CSV(json)).toString();
37
+ break;
38
+ // defaulting to JSON
39
+ default:
40
+ outputContent = JSON.stringify(json);
41
+ }
42
+ if (reports.directory) {
43
+ const date = new Date();
44
+ writeFileSync(path.join(`${reports.directory}`, `${reports.name}_${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}.${format.toLowerCase()}`), outputContent);
45
+ }
46
+ switch (output) {
47
+ case 'webhook':
48
+ if (!config.url) {
49
+ console.error('No valid Webhook URL given');
50
+ throw new Error('Please provide a valid --webhookUrl parameter');
51
+ }
52
+ try {
53
+ console.log(`Sending report via webhook to ${config.type} ....`);
54
+ await post2Webhook(config.type, config.url, config.title, outputContent, config.message);
55
+ console.log('Done sending.');
56
+ }
57
+ catch (e) {
58
+ switch (e.code || e.message) {
59
+ case 'Request failed with status code 400':
60
+ console.error('Invalid Teams Webhook Payload. Check your params.');
61
+ throw new Error('Invalid Teams Payload');
62
+ case 'slack_webhook_http_error':
63
+ console.error('Invalid Slack Webhook Payload. Check your params.');
64
+ throw new Error('Invalid Slack Payload');
65
+ default:
66
+ console.error(`Error during sending webhook.(${e === null || e === void 0 ? void 0 : e.code})`, e === null || e === void 0 ? void 0 : e.original);
67
+ throw e;
68
+ }
69
+ }
70
+ break;
71
+ // defaulting to standard out
72
+ default:
73
+ console.log(outputContent);
74
+ }
75
+ }
76
+ yargs(hideBin(process.argv))
77
+ .env()
78
+ .command('listUsers [url] [clientId] [clientSecret]', 'fetches all users in the realms.',
79
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
80
+ () => { }, async (argv) => {
81
+ const users = await listUsers(getKeycloakConfig(config, argv));
82
+ convertData(config, argv, 'user_listing', 'User Listing', users);
83
+ })
84
+ .command('listClients [url] [clientId] [clientSecret]', 'fetches all clients in the realms.',
85
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
86
+ () => { }, async (argv) => {
87
+ const clients = await listClients(getKeycloakConfig(config, argv));
88
+ convertData(config, argv, 'client_listing', 'Client Listing', clients);
89
+ })
90
+ .option('format', {
91
+ alias: 'f',
92
+ type: 'string',
93
+ default: 'json',
94
+ description: 'output format, e.g. JSON|CSV',
95
+ })
96
+ .option('output', {
97
+ alias: 'o',
98
+ type: 'string',
99
+ default: 'stdout',
100
+ description: 'output channel',
101
+ })
102
+ .option('webhookType', {
103
+ alias: 'w',
104
+ type: 'string',
105
+ default: 'slack',
106
+ description: 'Webhook Type',
107
+ })
108
+ .option('webhookMessage', {
109
+ alias: 'm',
110
+ type: 'string',
111
+ description: 'Webhook Message',
112
+ })
113
+ .option('webhookUrl', {
114
+ alias: 't',
115
+ type: 'string',
116
+ description: 'Webhook URL',
117
+ })
118
+ .option('reports', {
119
+ alias: 'r',
120
+ type: 'string',
121
+ description: 'Reports directory',
122
+ })
123
+ .option('useAuditingEndpoint', {
124
+ alias: 'a',
125
+ type: 'boolean',
126
+ default: false,
127
+ description: 'use auditior rest endpoint',
128
+ })
129
+ .command('configTest [url] [clientId] [clientSecret]', 'validates keycloak configuration by reading data via REST API',
130
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
131
+ () => { }, async (argv) => configTest(getKeycloakConfig(config, argv)))
132
+ .parse();
133
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ {
2
+ "$id": "https://github.com/ContinuousSecurityTooling/keycloak-reporter/blob/main/config/schema.json",
3
+ "$schema": "http://json-schema.org/draft-07/schema#",
4
+ "title": "Keycloak Reporter Config",
5
+ "type": "object",
6
+ "definitions": {},
7
+ "required": ["url", "clientId", "clientSecret"],
8
+ "properties": {
9
+ "command": {
10
+ "type": "array",
11
+ "items": {
12
+ "type": "string",
13
+ "enum": ["listClients", "listUsers"]
14
+ }
15
+ },
16
+ "url": {
17
+ "type": "string",
18
+ "description": "Keycloak Server URL"
19
+ },
20
+ "clientId": {
21
+ "type": "string",
22
+ "description": "Keycloak Client used for reporting"
23
+ },
24
+ "clientSecret": {
25
+ "type": "string",
26
+ "description": "Keycloak Client Secret used for reporting"
27
+ },
28
+ "output": {
29
+ "type": "array",
30
+ "items": {
31
+ "type": "string",
32
+ "enum": ["webhook", "stdout"]
33
+ },
34
+ "description": "Output channel to use"
35
+ },
36
+ "format": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "string",
40
+ "enum": ["json", "csv"]
41
+ },
42
+ "description": "Report format"
43
+ },
44
+ "webhookType": {
45
+ "type": "array",
46
+ "items": {
47
+ "type": "string",
48
+ "enum": ["slack", "teams"]
49
+ },
50
+ "description": "Type of webhook"
51
+ },
52
+ "webhookMessage": {
53
+ "type": "string",
54
+ "description": "Message added to the webhook post"
55
+ },
56
+ "webhookUrl": {
57
+ "type": "string",
58
+ "description": "URL of the webhook"
59
+ },
60
+ "reports": {
61
+ "type": "string",
62
+ "description": "Reports directory"
63
+ },
64
+ "useAuditingEndpoint": {
65
+ "type": "boolean",
66
+ "default": "false",
67
+ "description": "Enable usage of keycloak reporter auditing endpoint"
68
+ }
69
+ }
70
+ }
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { configTest, listUsers, listClients } from './src/commands.js';
2
+ export { convertJSON2CSV } from './lib/convert.js';
3
+ export { post2Webhook } from './lib/output.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import KcAdminClient from '@keycloak/keycloak-admin-client';
2
+ import { AuditClient } from '@continuoussecuritytooling/keycloak-auditor';
3
+ export async function createClient(options) {
4
+ const kcAdminClient = options.useAuditingEndpoint
5
+ ? new AuditClient(options.rootUrl, 'master')
6
+ : new KcAdminClient({
7
+ baseUrl: options.rootUrl,
8
+ realmName: 'master',
9
+ });
10
+ try {
11
+ // client login
12
+ await kcAdminClient.auth({
13
+ clientId: options.clientId,
14
+ clientSecret: options.clientSecret,
15
+ grantType: 'client_credentials',
16
+ });
17
+ }
18
+ catch (e) {
19
+ console.error('Check Client Config:', e.response ? e.response.data.error_description : e);
20
+ return Promise.reject();
21
+ }
22
+ return new Promise((resolve) => resolve(kcAdminClient));
23
+ }
24
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,6CAA6C,CAAC;AAS1E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAgB;IACjD,MAAM,aAAa,GAAG,OAAO,CAAC,mBAAmB;QAC/C,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC;QAC5C,CAAC,CAAC,IAAI,aAAa,CAAC;YAChB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;IACP,IAAI,CAAC;QACH,eAAe;QACf,MAAM,aAAa,CAAC,IAAI,CAAC;YACvB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,SAAS,EAAE,oBAAoB;SAChC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1F,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { AsyncParser } from '@json2csv/node';
2
+ export async function convertJSON2CSV(json) {
3
+ const opts = {};
4
+ const transformOpts = {};
5
+ const asyncOpts = {};
6
+ const parser = new AsyncParser(opts, transformOpts, asyncOpts);
7
+ return await parser.parse(json).promise();
8
+ }
9
+ //# sourceMappingURL=convert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convert.js","sourceRoot":"","sources":["../../lib/convert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,IAAI,GAAG,EAAE,CAAC;IAChB,MAAM,aAAa,GAAG,EAAE,CAAC;IACzB,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IAC/D,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { IncomingWebhook as TeamsWebhook } from 'ms-teams-webhook';
2
+ import { IncomingWebhook as SlackWebhook } from '@slack/webhook';
3
+ var WebhookType;
4
+ (function (WebhookType) {
5
+ WebhookType["SLACK"] = "slack";
6
+ WebhookType["TEAMS"] = "teams";
7
+ })(WebhookType || (WebhookType = {}));
8
+ export async function post2Webhook(type, url, title, reportContent, text) {
9
+ //const title= 'Keycloak Reporting';
10
+ const date = new Date();
11
+ switch (type) {
12
+ case WebhookType.TEAMS.toString():
13
+ return new TeamsWebhook(url).send({
14
+ type: 'message',
15
+ attachments: [
16
+ {
17
+ contentType: 'application/vnd.microsoft.card.adaptive',
18
+ content: {
19
+ $schema: 'https://adaptivecards.io/schemas/adaptive-card.json',
20
+ type: 'AdaptiveCard',
21
+ version: '1.2',
22
+ body: [
23
+ {
24
+ type: 'FactSet',
25
+ facts: [
26
+ {
27
+ title: 'Type',
28
+ value: title
29
+ },
30
+ {
31
+ title: 'Date',
32
+ value: `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ type: 'TextBlock',
38
+ text: text != null ? text : '',
39
+ wrap: true
40
+ }
41
+ ],
42
+ actions: [
43
+ {
44
+ type: 'Action.ShowCard',
45
+ title: 'Show raw report data',
46
+ card: {
47
+ type: 'AdaptiveCard',
48
+ body: [
49
+ {
50
+ type: 'TextBlock',
51
+ text: reportContent,
52
+ wrap: true
53
+ }
54
+ ],
55
+ $schema: 'https://adaptivecards.io/schemas/adaptive-card.json'
56
+ }
57
+ }
58
+ ]
59
+ }
60
+ }
61
+ ]
62
+ });
63
+ // defaulting to Slack
64
+ default:
65
+ // eslint-disable-next-line no-case-declarations
66
+ const blockEntries = [
67
+ {
68
+ type: 'section',
69
+ fields: [
70
+ { type: 'mrkdwn', text: `*Type*: ${title}` },
71
+ {
72
+ type: 'mrkdwn',
73
+ text: `*Date*: ${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ type: 'divider'
79
+ }
80
+ ];
81
+ if (text != null) {
82
+ blockEntries.push({
83
+ type: 'context',
84
+ elements: [{ type: 'plain_text', text: text }]
85
+ });
86
+ blockEntries.push({
87
+ type: 'divider'
88
+ });
89
+ }
90
+ blockEntries.push({
91
+ type: 'context',
92
+ elements: [
93
+ {
94
+ type: 'mrkdwn',
95
+ text: `
96
+ \`\`\`
97
+ ${reportContent}
98
+ \`\`\`
99
+ `
100
+ }
101
+ ]
102
+ }, {
103
+ type: 'context',
104
+ elements: [{ type: 'plain_text', text: 'Raw report data' }]
105
+ });
106
+ return new SlackWebhook(url).send({
107
+ blocks: blockEntries
108
+ });
109
+ }
110
+ }
111
+ /*
112
+ */
113
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../lib/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import KcAdminClient from '@keycloak/keycloak-admin-client';
2
+ export async function clientListing(client) {
3
+ let allClients = new Array();
4
+ if (client instanceof KcAdminClient) {
5
+ const currentRealm = client.realmName;
6
+ let realms;
7
+ try {
8
+ // iterate over realms
9
+ realms = await client.realms.find();
10
+ }
11
+ catch (e) {
12
+ console.error('Check Client role:', e.response.statusText);
13
+ return Promise.reject();
14
+ }
15
+ for (const realm of realms) {
16
+ // switch realm
17
+ client.setConfig({
18
+ realmName: realm.realm,
19
+ });
20
+ const realmClients = new Array();
21
+ for (const user of await client.clients.find()) {
22
+ realmClients.push({
23
+ client: user.clientId,
24
+ id: user.id,
25
+ description: user.description,
26
+ realm: realm.realm,
27
+ enabled: user.enabled,
28
+ public: user.publicClient,
29
+ allowedOrigins: JSON.stringify(user.webOrigins),
30
+ });
31
+ }
32
+ allClients = [...allClients, ...realmClients];
33
+ }
34
+ // switch back to realm
35
+ client.setConfig({
36
+ realmName: currentRealm,
37
+ });
38
+ }
39
+ else {
40
+ const clients = await client.clientListing();
41
+ for (const user of clients) {
42
+ allClients.push({
43
+ client: user.clientId,
44
+ id: user.id,
45
+ description: user.description,
46
+ realm: user.realm,
47
+ enabled: user.enabled,
48
+ public: user.publicClient,
49
+ lastLogin: user.lastLogin,
50
+ allowedOrigins: JSON.stringify(user.webOrigins),
51
+ });
52
+ }
53
+ }
54
+ return new Promise((resolve) => resolve(allClients));
55
+ }
56
+ export async function userListing(client) {
57
+ let allUsers = new Array();
58
+ if (client instanceof KcAdminClient) {
59
+ const currentRealm = client.realmName;
60
+ let realms;
61
+ // iterate over realms
62
+ try {
63
+ realms = await client.realms.find();
64
+ }
65
+ catch (e) {
66
+ console.error('Check Client role:', e.response.statusText);
67
+ return Promise.reject();
68
+ }
69
+ for (const realm of realms) {
70
+ // switch realm
71
+ client.setConfig({
72
+ realmName: realm.realm,
73
+ });
74
+ const realmUsers = new Array();
75
+ for (const user of await client.users.find()) {
76
+ realmUsers.push({
77
+ username: user.username,
78
+ id: user.id,
79
+ firstName: user.firstName,
80
+ lastName: user.lastName,
81
+ email: user.email,
82
+ realm: realm.realm,
83
+ enabled: user.enabled,
84
+ });
85
+ }
86
+ allUsers = [...allUsers, ...realmUsers];
87
+ }
88
+ // switch back to realm
89
+ client.setConfig({
90
+ realmName: currentRealm,
91
+ });
92
+ }
93
+ else {
94
+ const users = await client.userListing();
95
+ for (const user of users) {
96
+ allUsers.push({
97
+ username: user.username,
98
+ id: user.id,
99
+ firstName: user.firstName,
100
+ lastName: user.lastName,
101
+ email: user.email,
102
+ realm: user.realm,
103
+ lastLogin: user.lastLogin,
104
+ enabled: user.enabled,
105
+ });
106
+ }
107
+ }
108
+ return new Promise((resolve) => resolve(allUsers));
109
+ }
110
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../../lib/user.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { createClient } from '../lib/client.js';
2
+ import { userListing, clientListing } from '../lib/user.js';
3
+ function kcClient(options) {
4
+ return createClient({
5
+ clientId: options.clientId,
6
+ clientSecret: options.clientSecret,
7
+ rootUrl: options.rootUrl,
8
+ useAuditingEndpoint: options.useAuditingEndpoint,
9
+ });
10
+ }
11
+ export async function listUsers(options) {
12
+ const users = await userListing(await kcClient(options));
13
+ return new Promise((resolve) => resolve(users));
14
+ }
15
+ export async function listClients(options) {
16
+ const clients = await clientListing(await kcClient(options));
17
+ return new Promise((resolve) => resolve(clients));
18
+ }
19
+ /* eslint-disable @typescript-eslint/no-explicit-any */
20
+ export async function configTest(options) {
21
+ try {
22
+ await userListing(await kcClient(options));
23
+ console.log(`Connection to ${options.rootUrl} was successfull`);
24
+ }
25
+ catch (e) {
26
+ console.error(`Connection to ${options.rootUrl} was not: successfull`, e.response);
27
+ return Promise.reject(e.response.statusText);
28
+ }
29
+ }
30
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/commands.ts"],"names":[],"mappings":"AAMA,OAAO,EAAW,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAQ,WAAW,EAAE,aAAa,EAAU,MAAM,gBAAgB,CAAC;AAE1E,SAAS,QAAQ,CAAC,OAAgB;IAChC,OAAO,YAAY,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;KACjD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAgB;IAC9C,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACzD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AACpD,CAAC;AACD,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,CAAC,OAAO,kBAAkB,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,CAAC,OAAO,uBAAuB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;QACnF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { assoc, pick, mergeAll, mergeDeepRight } from 'ramda';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import fs from 'fs';
5
+ const schema = JSON.parse(fs.readFileSync(fileURLToPath(path.join(import.meta.url, '../../config/schema.json')), 'utf8'));
6
+ // import the config file
7
+ function buildConfigFromFile(filePath) {
8
+ if (!filePath)
9
+ return {};
10
+ const isAbsolutePath = filePath.charAt(0) === '/';
11
+ return JSON.parse(isAbsolutePath
12
+ ? fs.readFileSync(filePath, 'utf8')
13
+ : fs.readFileSync(fileURLToPath(path.join(import.meta.url, '../config', filePath)), 'utf8'));
14
+ }
15
+ // build an object using the defaults in the schema
16
+ function buildDefaults(schema, definitions) {
17
+ return Object.keys(schema.properties).reduce((acc, prop) => {
18
+ let spec = schema.properties[prop];
19
+ if (spec.$ref) {
20
+ spec = definitions[spec.$ref.replace('#/definitions/', '')];
21
+ if (spec && spec.type === 'object') {
22
+ return assoc(prop, buildDefaults(spec, definitions), acc);
23
+ }
24
+ }
25
+ return assoc(prop, spec.default, acc);
26
+ }, {});
27
+ }
28
+ // build an object of config values taken from process.env
29
+ function buildEnvironmentVariablesConfig(schema) {
30
+ const trueRx = /^true$/i;
31
+ const configKeys = Object.keys(schema.properties);
32
+ const env = pick(configKeys, process.env);
33
+ return Object.keys(env).reduce((acc, key) => {
34
+ const { type } = schema.properties[key];
35
+ switch (type) {
36
+ case 'integer':
37
+ return assoc(key, parseInt(env[key], 10), acc);
38
+ case 'boolean':
39
+ return assoc(key, trueRx.test(env[key]), acc);
40
+ default:
41
+ return assoc(key, env[key], acc);
42
+ }
43
+ }, {});
44
+ }
45
+ // merge the environment variables, config file values, and defaults
46
+ const config = mergeAll(mergeDeepRight(buildDefaults(schema, schema.definitions), buildConfigFromFile(process.env.CONFIG_FILE)), buildEnvironmentVariablesConfig(schema));
47
+ export default config;
48
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
@@ -21,7 +21,7 @@ test('Should list clients as JSON', { timeout: 3000 }, (t) => {
21
21
  }
22
22
  );
23
23
  cli.stdout.on('data', (chunk) => {
24
- console.log(chunk.toString())
24
+ console.log('Response', JSON.parse(chunk.toString()));
25
25
  t.equal(JSON.parse(chunk.toString()).length, 24);
26
26
  t.end();
27
27
  });
@@ -19,7 +19,7 @@ test('Should use config file', { timeout: 3000 }, (t) => {
19
19
  }
20
20
  );
21
21
  cli.stdout.on('data', (chunk) => {
22
- console.log(chunk.toString())
22
+ console.log('Response', JSON.parse(chunk.toString()));
23
23
  t.equal(JSON.parse(chunk.toString()).length, 24);
24
24
  t.end();
25
25
  });
@@ -27,3 +27,27 @@ test('Should use config file', { timeout: 3000 }, (t) => {
27
27
  t.fail(msg)
28
28
  });
29
29
  });
30
+
31
+ test('Should validate config', { timeout: 3000 }, (t) => {
32
+ const cli = spawn(
33
+ path.join(path.dirname('.'), 'node'),
34
+ [
35
+ 'dist/cli.js',
36
+ 'configTest'
37
+ ],
38
+ {
39
+ env: {
40
+ CONFIG_FILE: process.cwd() + '/e2e/fixtures/config.json',
41
+ ...process.env,
42
+ },
43
+ }
44
+ );
45
+ cli.stdout.on('data', (chunk) => {
46
+ console.log(chunk.toString())
47
+ t.equal(chunk.toString(), 'Connection to http://localhost:8080 was successfull\n');
48
+ t.end();
49
+ });
50
+ cli.stderr.on('data', (msg) => {
51
+ t.fail(msg)
52
+ });
53
+ });
package/e2e/spec/users.js CHANGED
@@ -21,7 +21,7 @@ test('Should list users as JSON', { timeout: 3000 }, (t) => {
21
21
  }
22
22
  );
23
23
  cli.stdout.on('data', (chunk) => {
24
- console.log(chunk.toString())
24
+ console.log('Response', JSON.parse(chunk.toString()));
25
25
  t.equal(JSON.parse(chunk.toString()).length, 3);
26
26
  t.end();
27
27
  });
package/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { listUsers, listClients } from './src/commands.js';
1
+ export { configTest, listUsers, listClients } from './src/commands.js';
2
2
  export { Options } from './lib/client.js';
3
3
  export { convertJSON2CSV } from './lib/convert.js';
4
- export { post2Webhook } from './lib/output.js';
4
+ export { post2Webhook } from './lib/output.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuoussecuritytooling/keycloak-reporter",
3
- "version": "0.7.0",
3
+ "version": "0.8.2",
4
4
  "description": "Reporting Tools for Keycloak",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "dependencies": {
28
28
  "@continuoussecuritytooling/keycloak-auditor": "^1.1.0",
29
29
  "@json2csv/node": "^7.0.0",
30
- "@keycloak/keycloak-admin-client": "^22.0.0",
30
+ "@keycloak/keycloak-admin-client": "^23.0.0",
31
31
  "@slack/webhook": "^7.0.0",
32
32
  "ajv": "^8.12.0",
33
33
  "install": "^0.13.0",
package/src/commands.ts CHANGED
@@ -25,3 +25,13 @@ export async function listClients(options: Options): Promise<Array<Client | Audi
25
25
  const clients = await clientListing(await kcClient(options));
26
26
  return new Promise((resolve) => resolve(clients));
27
27
  }
28
+ /* eslint-disable @typescript-eslint/no-explicit-any */
29
+ export async function configTest(options: Options): Promise<any> {
30
+ try {
31
+ await userListing(await kcClient(options));
32
+ console.log(`Connection to ${options.rootUrl} was successfull`);
33
+ } catch (e) {
34
+ console.error(`Connection to ${options.rootUrl} was not: successfull`, e.response);
35
+ return Promise.reject(e.response.statusText);
36
+ }
37
+ }
package/src/config.ts CHANGED
@@ -48,6 +48,7 @@ function buildEnvironmentVariablesConfig(schema) {
48
48
  }
49
49
  }, {});
50
50
  }
51
+
51
52
  // merge the environment variables, config file values, and defaults
52
53
  const config = mergeAll(
53
54
  mergeDeepRight(buildDefaults(schema, schema.definitions), buildConfigFromFile(process.env.CONFIG_FILE)),