From fc0ec7175f23fc5e7a9728e779916c37f1bf4ff4 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Fri, 15 Nov 2024 23:15:07 +0100 Subject: [PATCH 01/23] update reviewed prs prefix --- .../reviews-popover/reviews-popover.component.html | 2 +- .../leaderboard/reviews-popover/reviews-popover.component.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.html b/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.html index 6f24bed0..39cbad51 100644 --- a/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.html +++ b/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.html @@ -29,7 +29,7 @@

Reviewed PRs

@for (pullRequest of sortedReviewedPRs(); track pullRequest.id) { - {{ pullRequest.repository?.name ?? '' }}:{{ pullRequest.number }} + {{ pullRequest.repository?.name ?? '' }} #{{ pullRequest.number }} }
diff --git a/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.ts b/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.ts index 36ec90c7..083d25d0 100644 --- a/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.ts +++ b/webapp/src/app/home/leaderboard/reviews-popover/reviews-popover.component.ts @@ -53,13 +53,13 @@ export class ReviewsPopoverComponent { copyPullRequests() { const htmlList = ``; // As markdown text const plainText = this.sortedReviewedPRs() - .map((pullRequest) => `[${pullRequest.repository?.name ?? ''}:${pullRequest.number}](${pullRequest.htmlUrl})`) + .map((pullRequest) => `[${pullRequest.repository?.name ?? ''} #${pullRequest.number}](${pullRequest.htmlUrl})`) .join('\n'); const clipboardItem = new ClipboardItem({ From 2cae31db617e64a0175082554b7dfe2c839d56be Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:58:49 +0100 Subject: [PATCH 02/23] Fix: No Nats Connection Attempts if Disabled (#166) --- .../java/de/tum/in/www1/hephaestus/config/NatsConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/NatsConfig.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/NatsConfig.java index 36667e62..6ba65f46 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/NatsConfig.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/NatsConfig.java @@ -13,6 +13,9 @@ @Configuration public class NatsConfig { + @Value("${nats.enabled}") + private boolean isNatsEnabled; + @Value("${nats.server}") private String natsServer; @@ -21,7 +24,7 @@ public class NatsConfig { @Bean public Connection natsConnection() throws Exception { - if (environment.matchesProfiles("specs")) { + if (environment.matchesProfiles("specs") || !isNatsEnabled) { return null; } From fa04dbf22d6a10333480cea30149ae700362197f Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:01:26 +0100 Subject: [PATCH 03/23] Legend for the Leaderboard (#165) --- webapp/src/app/home/home.component.html | 5 +- webapp/src/app/home/home.component.ts | 3 +- .../leaderboard/legend/legend.component.html | 49 +++++++++++++++++++ .../home/leaderboard/legend/legend.stories.ts | 15 ++++++ .../leaderboard/legend/legends.component.ts | 32 ++++++++++++ 5 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 webapp/src/app/home/leaderboard/legend/legend.component.html create mode 100644 webapp/src/app/home/leaderboard/legend/legend.stories.ts create mode 100644 webapp/src/app/home/leaderboard/legend/legends.component.ts diff --git a/webapp/src/app/home/home.component.html b/webapp/src/app/home/home.component.html index 2d9fd936..abc88a0f 100644 --- a/webapp/src/app/home/home.component.html +++ b/webapp/src/app/home/home.component.html @@ -23,8 +23,9 @@

Something went wrong...

} - -
+
+ +
diff --git a/webapp/src/app/home/home.component.ts b/webapp/src/app/home/home.component.ts index d6dc8d54..9af395cc 100644 --- a/webapp/src/app/home/home.component.ts +++ b/webapp/src/app/home/home.component.ts @@ -12,13 +12,14 @@ import { LeaderboardFilterComponent } from './leaderboard/filter/filter.componen import { SecurityStore } from '@app/core/security/security-store.service'; import { HlmAlertModule } from '@spartan-ng/ui-alert-helm'; import { MetaService } from '@app/core/modules/openapi'; +import { LeaderboardLegendComponent } from './leaderboard/legend/legends.component'; dayjs.extend(isoWeek); @Component({ selector: 'app-home', standalone: true, - imports: [LeaderboardComponent, LeaderboardFilterComponent, HlmAlertModule, LucideAngularModule], + imports: [LeaderboardComponent, LeaderboardFilterComponent, HlmAlertModule, LucideAngularModule, LeaderboardLegendComponent], templateUrl: './home.component.html' }) export class HomeComponent { diff --git a/webapp/src/app/home/leaderboard/legend/legend.component.html b/webapp/src/app/home/leaderboard/legend/legend.component.html new file mode 100644 index 00000000..bc4b2be0 --- /dev/null +++ b/webapp/src/app/home/leaderboard/legend/legend.component.html @@ -0,0 +1,49 @@ +
+
+
+

Leaderboard Legend

+

Explanation of the most important elements

+
+
+ @if (open()) { + + } @else { + + } +
+
+
+
+

Icons

+
+ + Reviewed pull requests +
+
+ + Changes requested +
+
+ + Approvals +
+
+ + Comments +
+
+ + Code comments +
+
+
+

Scoring System

+

+ The score represents an approximation of the account's contribution activity. Different types of review interactions are weighted + according to pre-defined metrics, with constructive feedback like change requests valued highest. Additional points are awarded for reviewing more complex pull requests + based on their size and scope. As a result, the score is not a direct representation of the reviewer's time investment or quality of + work. +

+
+
+
diff --git a/webapp/src/app/home/leaderboard/legend/legend.stories.ts b/webapp/src/app/home/leaderboard/legend/legend.stories.ts new file mode 100644 index 00000000..4e4854d7 --- /dev/null +++ b/webapp/src/app/home/leaderboard/legend/legend.stories.ts @@ -0,0 +1,15 @@ +import { type Meta, type StoryObj } from '@storybook/angular'; +import { LeaderboardLegendComponent } from './legends.component'; + +const meta: Meta = { + component: LeaderboardLegendComponent, + tags: ['autodocs'], + parameters: { + layout: 'centered' + } +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/webapp/src/app/home/leaderboard/legend/legends.component.ts b/webapp/src/app/home/leaderboard/legend/legends.component.ts new file mode 100644 index 00000000..79254c8a --- /dev/null +++ b/webapp/src/app/home/leaderboard/legend/legends.component.ts @@ -0,0 +1,32 @@ +import { Component, computed, input, signal } from '@angular/core'; +import { NgIconComponent } from '@ng-icons/core'; +import { octFileDiff, octCheck, octComment, octCommentDiscussion, octGitPullRequest } from '@ng-icons/octicons'; +import { HlmIconComponent } from '@spartan-ng/ui-icon-helm'; +import { HlmCardModule } from '@spartan-ng/ui-card-helm'; +import { provideIcons } from '@spartan-ng/ui-icon-helm'; +import { lucideChevronsDown, lucideChevronsUp } from '@ng-icons/lucide'; +import { cn } from '@app/utils'; + +@Component({ + selector: 'app-leaderboard-legend', + standalone: true, + imports: [HlmCardModule, NgIconComponent, HlmIconComponent], + providers: [provideIcons({ lucideChevronsDown, lucideChevronsUp })], + templateUrl: './legend.component.html' +}) +export class LeaderboardLegendComponent { + protected octFileDiff = octFileDiff; + protected octCheck = octCheck; + protected octComment = octComment; + protected octCommentDiscussion = octCommentDiscussion; + protected octGitPullRequest = octGitPullRequest; + + isLoading = input(); + open = signal(false); + + contentClass = computed(() => cn('flex flex-wrap gap-y-4 gap-x-8 pt-2', { hidden: !this.open() })); + + toggleOpen() { + this.open.set(!this.open()); + } +} From decf67f9291afa6878658109439d403ea143dc9e Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Mon, 18 Nov 2024 20:18:31 +0100 Subject: [PATCH 04/23] prevent felix from being employee of the month --- .../www1/hephaestus/leaderboard/LeaderboardService.java | 2 +- .../src/app/home/leaderboard/legend/legend.component.html | 8 ++++++++ .../src/app/home/leaderboard/legend/legends.component.ts | 3 ++- .../ui/ui-button-helm/src/lib/hlm-button.directive.ts | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java index d5e930ab..c4b0ee03 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java @@ -198,7 +198,7 @@ private int calculateTotalScore(List reviews, int numberOfIss (approvalReviews * 1.5 + changesRequestedReviews * 2.0 + (commentReviews + unknownReviews + numberOfIssueComments) + - codeComments * 0.5); + codeComments * 0.25); double complexityBonus = 1 + (complexityScore - 1) / 32.0; diff --git a/webapp/src/app/home/leaderboard/legend/legend.component.html b/webapp/src/app/home/leaderboard/legend/legend.component.html index bc4b2be0..c8ea03b8 100644 --- a/webapp/src/app/home/leaderboard/legend/legend.component.html +++ b/webapp/src/app/home/leaderboard/legend/legend.component.html @@ -43,6 +43,14 @@

Scoring System

according to pre-defined metrics, with constructive feedback like change requests valued highest. Additional points are awarded for reviewing more complex pull requests based on their size and scope. As a result, the score is not a direct representation of the reviewer's time investment or quality of work. + + [source] +

diff --git a/webapp/src/app/home/leaderboard/legend/legends.component.ts b/webapp/src/app/home/leaderboard/legend/legends.component.ts index 79254c8a..bc6da240 100644 --- a/webapp/src/app/home/leaderboard/legend/legends.component.ts +++ b/webapp/src/app/home/leaderboard/legend/legends.component.ts @@ -6,11 +6,12 @@ import { HlmCardModule } from '@spartan-ng/ui-card-helm'; import { provideIcons } from '@spartan-ng/ui-icon-helm'; import { lucideChevronsDown, lucideChevronsUp } from '@ng-icons/lucide'; import { cn } from '@app/utils'; +import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; @Component({ selector: 'app-leaderboard-legend', standalone: true, - imports: [HlmCardModule, NgIconComponent, HlmIconComponent], + imports: [HlmCardModule, NgIconComponent, HlmIconComponent, HlmButtonDirective], providers: [provideIcons({ lucideChevronsDown, lucideChevronsUp })], templateUrl: './legend.component.html' }) diff --git a/webapp/src/libs/ui/ui-button-helm/src/lib/hlm-button.directive.ts b/webapp/src/libs/ui/ui-button-helm/src/lib/hlm-button.directive.ts index 35e39e84..157d2ab2 100644 --- a/webapp/src/libs/ui/ui-button-helm/src/lib/hlm-button.directive.ts +++ b/webapp/src/libs/ui/ui-button-helm/src/lib/hlm-button.directive.ts @@ -16,6 +16,7 @@ export const buttonVariants = cva( link: 'underline-offset-4 hover:underline text-primary' }, size: { + none: '', default: 'h-10 py-2 px-4', sm: 'h-9 px-3 rounded-md', lg: 'h-11 px-8 rounded-md', From 961614388f7860319a076089be0095190bf20a71 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Mon, 18 Nov 2024 21:30:23 +0100 Subject: [PATCH 05/23] update scoring --- .../leaderboard/LeaderboardService.java | 68 ++++++++++++------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java index c4b0ee03..2ada550b 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardService.java @@ -170,39 +170,34 @@ private int calculateTotalScore(List reviews, int numberOfIss // All reviews are for the same pull request int complexityScore = calculateComplexityScore(pullRequestReviews.get(0).getPullRequest()); - int approvalReviews = (int) pullRequestReviews + double approvalWeight = 2.0; + double approvalScore = pullRequestReviews .stream() .filter(review -> review.getState() == PullRequestReview.State.APPROVED) - .count(); - int changesRequestedReviews = (int) pullRequestReviews + .filter(review -> review.getAuthor().getId() != review.getPullRequest().getAuthor().getId()) + .map(review -> approvalWeight * calculateCodeReviewBonus(review.getComments().size(), complexityScore)) + .reduce(0.0, Double::sum); + + double changesRequestedWeight = 2.5; + double changesRequestedScore = pullRequestReviews .stream() .filter(review -> review.getState() == PullRequestReview.State.CHANGES_REQUESTED) - .count(); - int commentReviews = (int) pullRequestReviews - .stream() - .filter(review -> review.getState() == PullRequestReview.State.COMMENTED) - .filter(review -> review.getBody() != null) // Only count if there is a comment - .count(); - int unknownReviews = (int) pullRequestReviews - .stream() - .filter(review -> review.getState() == PullRequestReview.State.UNKNOWN) - .filter(review -> review.getBody() != null) // Only count if there is a comment - .count(); + .filter(review -> review.getAuthor().getId() != review.getPullRequest().getAuthor().getId()) + .map(review -> changesRequestedWeight * calculateCodeReviewBonus(review.getComments().size(), complexityScore)) + .reduce(0.0, Double::sum); - int codeComments = pullRequestReviews + double commentWeight = 1.5; + double commentScore = pullRequestReviews .stream() - .map(review -> review.getComments().size()) - .reduce(0, Integer::sum); - - double interactionScore = - (approvalReviews * 1.5 + - changesRequestedReviews * 2.0 + - (commentReviews + unknownReviews + numberOfIssueComments) + - codeComments * 0.25); + .filter(review -> review.getState() == PullRequestReview.State.COMMENTED || review.getState() == PullRequestReview.State.UNKNOWN) + .filter(review -> review.getAuthor().getId() != review.getPullRequest().getAuthor().getId()) + .map(review -> commentWeight * calculateCodeReviewBonus(review.getComments().size(), complexityScore)) + .reduce(0.0, Double::sum); - double complexityBonus = 1 + (complexityScore - 1) / 32.0; + double issueCommentScore = commentWeight * numberOfIssueComments; - return 5 * interactionScore * complexityBonus; + double interactionScore = approvalScore + changesRequestedScore + commentScore + issueCommentScore; + return 10 * interactionScore * complexityScore / (interactionScore + complexityScore); }) .reduce(0.0, Double::sum); return (int) Math.ceil(totalScore); @@ -234,4 +229,27 @@ private int calculateComplexityScore(PullRequest pullRequest) { } return 33; // Overly complex } + + /** + * Calculates the code review bonus for a given number of code comments and complexity score. + * The bonus is a value between 0 and 2. + * Taken from the original leaderboard implementation script. + * + * @param codeComments + * @param complexityScore + * @return bonus + */ + private double calculateCodeReviewBonus(int codeComments, int complexityScore) { + double maxBonus = 2; + + double codeReviewBonus = 1; + if (codeComments < complexityScore) { + // Function goes from 0 at codeComments = 0 to 1 at codeComments = complexityScore + codeReviewBonus += 2 * Math.sqrt(complexityScore) * Math.sqrt(codeComments) / (codeComments + complexityScore); + } else { + // Saturate at 1 + codeReviewBonus += 1; + } + return codeReviewBonus / 2 * maxBonus; + } } From 9abe4c51d1ae5987764df6589dcac56ef16226a9 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Mon, 18 Nov 2024 21:30:50 +0100 Subject: [PATCH 06/23] update legend --- .../home/leaderboard/legend/legend.component.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/webapp/src/app/home/leaderboard/legend/legend.component.html b/webapp/src/app/home/leaderboard/legend/legend.component.html index c8ea03b8..b3178176 100644 --- a/webapp/src/app/home/leaderboard/legend/legend.component.html +++ b/webapp/src/app/home/leaderboard/legend/legend.component.html @@ -39,15 +39,17 @@

Icons

Scoring System

- The score represents an approximation of the account's contribution activity. Different types of review interactions are weighted - according to pre-defined metrics, with constructive feedback like change requests valued highest. Additional points are awarded for reviewing more complex pull requests - based on their size and scope. As a result, the score is not a direct representation of the reviewer's time investment or quality of - work. + The score approximates your contribution activity by evaluating your review interactions and the complexity of the pull requests you've reviewed. + Change requests are valued highest, followed by approvals and comments. The score increases with the number of review interactions. Pull + request complexity — based on factors like changed files, commits, additions, and deletions — also enhances your score; + more complex pull requests contribute more. The final score balances your interactions with the complexity of the work reviewed, + highlighting both your engagement and the difficulty of the tasks you've undertaken. This score reflects your impact but does not directly measure time invested or work + quality. [source] From 038ffd0072a52ac2a9d4d90af0f056dd2f108d60 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 10:59:20 +0100 Subject: [PATCH 07/23] update scripts --- package.json | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 4d3b55d3..5b6179f9 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,12 @@ ], "scripts": { "generate:api:application-server:clean": "shx rm -rf webapp/src/app/core/modules/openapi", - "generate:api:intelligence-service:clean": "shx rm -rf server/application-server/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice", - "generate:api:clean": "npm run generate:api:intelligence-service:clean && npm run generate:api:application-server:clean", - "generate:api:application-server-specs": "cd server/application-server && mvn verify -DskipTests=true -Dapp.profiles=specs", - "generate:api:intelligence-service-specs": "python -m server.intelligence-service.app.generate_openapi_yaml", - "generate:api:specs": "npm run generate:api:application-server-specs && npm run generate:api:intelligence-service-specs", - "generate:api:application-server-client": "npx openapi-generator-cli generate -i server/application-server/openapi.yaml -g typescript-angular -o webapp/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model", - "generate:api:intelligence-service-client": "npx openapi-generator-cli generate -i server/intelligence-service/openapi.yaml -g java --library resttemplate --api-package de.tum.in.www1.hephaestus.intelligenceservice.api --model-package de.tum.in.www1.hephaestus.intelligenceservice.model --invoker-package de.tum.in.www1.hephaestus.intelligenceservice --additional-properties useJakartaEe=true,performBeanValidation=true,generateClientAsBean=true,hideGenerationTimestamp=true --package-name de.tum.in.www1.hephaestus.intelligenceservice -o tmp/java-client && shx cp -r tmp/java-client/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice server/application-server/src/main/java/de/tum/in/www1/hephaestus && shx rm -rf tmp", - "generate:api:clients": "npm run generate:api:intelligence-service-client && npm run generate:api:application-server-client", + "generate:api:application-server:specs": "cd server/application-server && mvn verify -DskipTests=true -Dapp.profiles=specs", + "generate:api:application-server:client": "npx openapi-generator-cli generate -i server/application-server/openapi.yaml -g typescript-angular -o webapp/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model", "generate:api:application-server": "npm run generate:api:application-server-specs && npm run generate:api:application-server:clean && npm run generate:api:application-server-client", + "generate:api:intelligence-service:clean": "shx rm -rf server/application-server/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice", + "generate:api:intelligence-service:specs": "python -m server.intelligence-service.app.generate_openapi_yaml", + "generate:api:intelligence-service:client": "npx openapi-generator-cli generate -i server/intelligence-service/openapi.yaml -g java --library resttemplate --api-package de.tum.in.www1.hephaestus.intelligenceservice.api --model-package de.tum.in.www1.hephaestus.intelligenceservice.model --invoker-package de.tum.in.www1.hephaestus.intelligenceservice --additional-properties useJakartaEe=true,performBeanValidation=true,generateClientAsBean=true,hideGenerationTimestamp=true --package-name de.tum.in.www1.hephaestus.intelligenceservice -o tmp/java-client && shx cp -r tmp/java-client/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice server/application-server/src/main/java/de/tum/in/www1/hephaestus && shx rm -rf tmp", "generate:api:intelligence-service": "npm run generate:api:intelligence-service:clean && npm run generate:api:intelligence-service-specs && npm run generate:api:intelligence-service-client", "generate:api": "npm run generate:api:intelligence-service && npm run generate:api:application-server", "format:java:check": "prettier --check server/application-server/src/**/*.java", From d456eafec19ba933a78b246fef2a1bef36689f62 Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:09:08 +0100 Subject: [PATCH 08/23] Fix: Show new Leaderboard instantly (#171) --- webapp/src/app/home/home.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/app/home/home.component.ts b/webapp/src/app/home/home.component.ts index 9af395cc..6cf81c01 100644 --- a/webapp/src/app/home/home.component.ts +++ b/webapp/src/app/home/home.component.ts @@ -49,7 +49,7 @@ export class HomeComponent { if (afterParam) return afterParam; let defaultDate = dayjs().isoWeekday(this.leaderboardSchedule().day).startOf('hour').hour(this.leaderboardSchedule().hour).minute(this.leaderboardSchedule().minute); - if (defaultDate.isAfter(dayjs()) || defaultDate.isSame(dayjs(), 'day')) { + if (defaultDate.isAfter(dayjs())) { defaultDate = defaultDate.subtract(1, 'week'); } return defaultDate.format(); From 42bcda752bbc5ecb7983f9bc89904ba2e773f2ee Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:58:17 +0100 Subject: [PATCH 09/23] Fix: Colon in Combined `NPM`-Commands (#179) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5b6179f9..d14c1b22 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,11 @@ "generate:api:application-server:clean": "shx rm -rf webapp/src/app/core/modules/openapi", "generate:api:application-server:specs": "cd server/application-server && mvn verify -DskipTests=true -Dapp.profiles=specs", "generate:api:application-server:client": "npx openapi-generator-cli generate -i server/application-server/openapi.yaml -g typescript-angular -o webapp/src/app/core/modules/openapi --additional-properties fileNaming=kebab-case,withInterfaces=true --generate-alias-as-model", - "generate:api:application-server": "npm run generate:api:application-server-specs && npm run generate:api:application-server:clean && npm run generate:api:application-server-client", + "generate:api:application-server": "npm run generate:api:application-server:specs && npm run generate:api:application-server:clean && npm run generate:api:application-server:client", "generate:api:intelligence-service:clean": "shx rm -rf server/application-server/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice", "generate:api:intelligence-service:specs": "python -m server.intelligence-service.app.generate_openapi_yaml", "generate:api:intelligence-service:client": "npx openapi-generator-cli generate -i server/intelligence-service/openapi.yaml -g java --library resttemplate --api-package de.tum.in.www1.hephaestus.intelligenceservice.api --model-package de.tum.in.www1.hephaestus.intelligenceservice.model --invoker-package de.tum.in.www1.hephaestus.intelligenceservice --additional-properties useJakartaEe=true,performBeanValidation=true,generateClientAsBean=true,hideGenerationTimestamp=true --package-name de.tum.in.www1.hephaestus.intelligenceservice -o tmp/java-client && shx cp -r tmp/java-client/src/main/java/de/tum/in/www1/hephaestus/intelligenceservice server/application-server/src/main/java/de/tum/in/www1/hephaestus && shx rm -rf tmp", - "generate:api:intelligence-service": "npm run generate:api:intelligence-service:clean && npm run generate:api:intelligence-service-specs && npm run generate:api:intelligence-service-client", + "generate:api:intelligence-service": "npm run generate:api:intelligence-service:clean && npm run generate:api:intelligence-service:specs && npm run generate:api:intelligence-service:client", "generate:api": "npm run generate:api:intelligence-service && npm run generate:api:application-server", "format:java:check": "prettier --check server/application-server/src/**/*.java", "format:java:write": "prettier --write server/application-server/src/**/*.java", From bcda81204e2ac139ac2e3a61f8e03c508536b2d5 Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:07:01 +0100 Subject: [PATCH 10/23] Fix: Add After + Before to Leaderboard Link (#178) Co-authored-by: Felix T.J. Dietrich --- .../leaderboard/SlackMessageService.java | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/SlackMessageService.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/SlackMessageService.java index 2142b103..847a7a83 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/SlackMessageService.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/SlackMessageService.java @@ -144,20 +144,10 @@ public void run() { private class SlackWeeklyLeaderboardTask implements Runnable { /** - * Gets the Slack handles of the top 3 reviewers of the last week. + * Gets the Slack handles of the top 3 reviewers in the given time frame. * @return */ - private List getTop3SlackReviewers() { - // Calculate the the last leaderboard schedule - var timeParts = scheduledTime.split(":"); - OffsetDateTime before = OffsetDateTime.now() - .with(TemporalAdjusters.previousOrSame(DayOfWeek.of(Integer.parseInt(scheduledDay)))) - .withHour(Integer.parseInt(timeParts[0])) - .withMinute(timeParts.length > 0 ? Integer.parseInt(timeParts[1]) : 0) - .withSecond(0) - .withNano(0); - OffsetDateTime after = before.minusWeeks(1); - + private List getTop3SlackReviewers(OffsetDateTime after, OffsetDateTime before) { var leaderboard = leaderboardService.createLeaderboard(after, before, Optional.empty()); var top3 = leaderboard.subList(0, Math.min(3, leaderboard.size())); logger.debug("Top 3 Users of the last week: " + top3.stream().map(e -> e.user().name()).toList()); @@ -170,11 +160,7 @@ private List getTop3SlackReviewers() { return new ArrayList<>(); } - return top3 - .stream() - .map(mapToSlackUser(allSlackUsers)) - .filter(user -> user != null) - .toList(); + return top3.stream().map(mapToSlackUser(allSlackUsers)).filter(user -> user != null).toList(); } private Function mapToSlackUser(List allSlackUsers) { @@ -205,14 +191,28 @@ private Function mapToSlackUser(List allSlackUs }; } + private String formatDateForURL(OffsetDateTime date) { + return date.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME).replace("+", "%2B"); + } + @Override public void run() { // get date in unix format - var currentDate = OffsetDateTime.now().toEpochSecond(); + long currentDate = OffsetDateTime.now().toEpochSecond(); + // Calculate the the last leaderboard schedule + String[] timeParts = scheduledTime.split(":"); + OffsetDateTime before = OffsetDateTime.now() + .with(TemporalAdjusters.previousOrSame(DayOfWeek.of(Integer.parseInt(scheduledDay)))) + .withHour(Integer.parseInt(timeParts[0])) + .withMinute(timeParts.length > 0 ? Integer.parseInt(timeParts[1]) : 0) + .withSecond(0) + .withNano(0); + OffsetDateTime after = before.minusWeeks(1); - var top3reviewers = getTop3SlackReviewers(); + var top3reviewers = getTop3SlackReviewers(after, before); logger.info("Sending scheduled message to Slack channel..."); + List blocks = asBlocks( header(header -> header.text(plainText(pt -> pt.text(":newspaper: Reviews of the last week :newspaper:"))) @@ -232,6 +232,10 @@ public void run() { markdownText( "Another *review leaderboard* has concluded. You can check out your placement <" + hephaestusUrl + + "?after=" + + formatDateForURL(after) + + "&before=" + + formatDateForURL(before) + "|here>." ) ) From ed9088c13915887c71149f09790520fe76274b19 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 19:58:01 +0100 Subject: [PATCH 11/23] Add imprint (#180) --- webapp/Dockerfile | 3 ++ webapp/package-lock.json | 45 +++++++++++++++++++ webapp/package.json | 1 + webapp/src/app/app.routes.ts | 4 +- .../src/app/core/footer/footer.component.html | 3 ++ .../app/legal/imprint/imprint.component.ts | 16 +++++++ webapp/src/environments/environment.prod.ts | 3 ++ webapp/src/environments/environment.ts | 3 ++ webapp/tailwind.config.ts | 5 ++- 9 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 webapp/src/app/legal/imprint/imprint.component.ts diff --git a/webapp/Dockerfile b/webapp/Dockerfile index f3354666..777cab6a 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -33,6 +33,9 @@ export const environment = { scriptUrl: '${UMAMI_SCRIPT_URL}', websiteId: '${UMAMI_WEBSITE_ID}', domains: '${UMAMI_DOMAINS}' + }, + legal: { + imprintHtml: '${LEGAL_IMPRINT_HTML}', } }; EOF diff --git a/webapp/package-lock.json b/webapp/package-lock.json index cbdcc113..19f24322 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -78,6 +78,7 @@ "@storybook/angular": "8.3.4", "@storybook/blocks": "8.3.4", "@storybook/test": "8.3.4", + "@tailwindcss/typography": "0.5.15", "@types/jasmine": "5.1.4", "@typescript-eslint/eslint-plugin": "8.2.0", "@typescript-eslint/parser": "8.2.0", @@ -7853,6 +7854,36 @@ "storybook": "^8.3.4" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.15.tgz", + "integrity": "sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@tanstack/angular-query-devtools-experimental": { "version": "5.52.0", "resolved": "https://registry.npmjs.org/@tanstack/angular-query-devtools-experimental/-/angular-query-devtools-experimental-5.52.0.tgz", @@ -16082,6 +16113,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.clonedeepwith": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeepwith/-/lodash.clonedeepwith-4.5.0.tgz", @@ -16094,6 +16132,13 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", diff --git a/webapp/package.json b/webapp/package.json index 6638aced..1aa1854f 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -90,6 +90,7 @@ "@storybook/angular": "8.3.4", "@storybook/blocks": "8.3.4", "@storybook/test": "8.3.4", + "@tailwindcss/typography": "0.5.15", "@types/jasmine": "5.1.4", "@typescript-eslint/eslint-plugin": "8.2.0", "@typescript-eslint/parser": "8.2.0", diff --git a/webapp/src/app/app.routes.ts b/webapp/src/app/app.routes.ts index 905e9a4f..e8cc848a 100644 --- a/webapp/src/app/app.routes.ts +++ b/webapp/src/app/app.routes.ts @@ -4,6 +4,7 @@ import { HomeComponent } from '@app/home/home.component'; import { AdminComponent } from '@app/admin/admin.component'; import { AdminGuard } from '@app/core/security/admin.guard'; import { UserProfileComponent } from '@app/user/user-profile.component'; +import { ImprintComponent } from '@app/legal/imprint/imprint.component'; export const routes: Routes = [ { path: '', component: HomeComponent }, @@ -13,5 +14,6 @@ export const routes: Routes = [ component: AdminComponent, canActivate: [AdminGuard] }, - { path: 'user/:id', component: UserProfileComponent } + { path: 'user/:id', component: UserProfileComponent }, + { path: 'imprint', component: ImprintComponent } ]; diff --git a/webapp/src/app/core/footer/footer.component.html b/webapp/src/app/core/footer/footer.component.html index 83df74a0..caa682ec 100644 --- a/webapp/src/app/core/footer/footer.component.html +++ b/webapp/src/app/core/footer/footer.component.html @@ -3,6 +3,9 @@

About

+

+ Imprint +

Feature requests

diff --git a/webapp/src/app/legal/imprint/imprint.component.ts b/webapp/src/app/legal/imprint/imprint.component.ts new file mode 100644 index 00000000..ac058e05 --- /dev/null +++ b/webapp/src/app/legal/imprint/imprint.component.ts @@ -0,0 +1,16 @@ +import { Component } from '@angular/core'; +import { environment } from 'environments/environment'; + +@Component({ + selector: 'app-imprint', + standalone: true, + template: ` +
+

Imprint

+
+
+ ` +}) +export class ImprintComponent { + imprintHtml = environment.legal.imprintHtml; +} diff --git a/webapp/src/environments/environment.prod.ts b/webapp/src/environments/environment.prod.ts index 50220235..e4679dd2 100644 --- a/webapp/src/environments/environment.prod.ts +++ b/webapp/src/environments/environment.prod.ts @@ -12,5 +12,8 @@ export const environment = { scriptUrl: '', websiteId: '', domains: '' + }, + legal: { + imprintHtml: '

This is the imprint.

' } }; diff --git a/webapp/src/environments/environment.ts b/webapp/src/environments/environment.ts index 023fa93f..acd528ad 100644 --- a/webapp/src/environments/environment.ts +++ b/webapp/src/environments/environment.ts @@ -12,5 +12,8 @@ export const environment = { scriptUrl: '', websiteId: '', domains: '' + }, + legal: { + imprintHtml: '

This is the imprint.

' } }; diff --git a/webapp/tailwind.config.ts b/webapp/tailwind.config.ts index 9f8f6874..9a8b8a5b 100644 --- a/webapp/tailwind.config.ts +++ b/webapp/tailwind.config.ts @@ -148,7 +148,10 @@ const config = { }, }, }, - plugins: [require("tailwindcss-animate")], + plugins: [ + require("tailwindcss-animate"), + require('@tailwindcss/typography'), + ], } satisfies Config export default config From 2325a84753b21f398e1bc7d77238a015f4f6c3fa Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 19:59:06 +0100 Subject: [PATCH 12/23] fix trailing comma --- webapp/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 777cab6a..f0fb59b2 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -35,7 +35,7 @@ export const environment = { domains: '${UMAMI_DOMAINS}' }, legal: { - imprintHtml: '${LEGAL_IMPRINT_HTML}', + imprintHtml: '${LEGAL_IMPRINT_HTML}' } }; EOF From 6fc02c93dc675f9757d7e7efb32cf93cf9314b5e Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 20:33:37 +0100 Subject: [PATCH 13/23] update dockerfile --- webapp/Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index f0fb59b2..87baa6f5 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -1,4 +1,4 @@ -FROM node:latest as build +FROM node:latest AS build WORKDIR /app @@ -16,7 +16,9 @@ RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ # Export environment variables from .env # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' -RUN export $(grep -v '^#' .env | xargs) && \ +RUN set -a && \ + . .env && \ + set +a && \ echo "Generating environment.prod.ts" && \ cat > src/environments/environment.prod.ts < Date: Tue, 19 Nov 2024 20:43:24 +0100 Subject: [PATCH 14/23] source env correctly? --- webapp/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 87baa6f5..1a099fa4 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -1,4 +1,4 @@ -FROM node:latest AS build +FROM node:latest as build WORKDIR /app @@ -17,7 +17,7 @@ RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' RUN set -a && \ - . .env && \ + source .env && \ set +a && \ echo "Generating environment.prod.ts" && \ cat > src/environments/environment.prod.ts < Date: Tue, 19 Nov 2024 20:46:02 +0100 Subject: [PATCH 15/23] fix error --- webapp/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 1a099fa4..9dcc3f39 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -17,7 +17,7 @@ RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' RUN set -a && \ - source .env && \ + . .env && \ set +a && \ echo "Generating environment.prod.ts" && \ cat > src/environments/environment.prod.ts < Date: Tue, 19 Nov 2024 20:48:47 +0100 Subject: [PATCH 16/23] add debug command --- webapp/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 9dcc3f39..f8d2b59e 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -13,6 +13,11 @@ RUN cat .env RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ sed -i "s|\$COOLIFY_URL|$COOLIFY_URL_VALUE|g" .env + +RUN ls -la /app + +RUN ls -la . + # Export environment variables from .env # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' From 3db5fff2f1c2d7648612bc1366be44e6bc0cfcce Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 20:52:01 +0100 Subject: [PATCH 17/23] add more debug statements --- webapp/Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index f8d2b59e..141e6acb 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -22,7 +22,11 @@ RUN ls -la . # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' RUN set -a && \ - . .env && \ + echo "Listing /app directory:" && \ + ls -la /app && \ + echo "Displaying contents of /app/.env:" && \ + cat /app/.env && \ + . /app/.env && \ set +a && \ echo "Generating environment.prod.ts" && \ cat > src/environments/environment.prod.ts < Date: Tue, 19 Nov 2024 20:53:19 +0100 Subject: [PATCH 18/23] remove debug statements --- webapp/Dockerfile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 141e6acb..9ab2755b 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -13,19 +13,10 @@ RUN cat .env RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ sed -i "s|\$COOLIFY_URL|$COOLIFY_URL_VALUE|g" .env - -RUN ls -la /app - -RUN ls -la . - # Export environment variables from .env # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' -RUN set -a && \ - echo "Listing /app directory:" && \ - ls -la /app && \ - echo "Displaying contents of /app/.env:" && \ - cat /app/.env && \ +RUN set -a && \\ . /app/.env && \ set +a && \ echo "Generating environment.prod.ts" && \ From 7ca3e728d328be9d152691eafefd79a2fd732002 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 21:03:29 +0100 Subject: [PATCH 19/23] fix trailing slash --- webapp/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/Dockerfile b/webapp/Dockerfile index 9ab2755b..1165c4af 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -16,7 +16,7 @@ RUN COOLIFY_URL_VALUE=$(grep '^COOLIFY_URL=' .env | cut -d '=' -f2) && \ # Export environment variables from .env # This assumes that .env contains lines like VARIABLE=value # and does not contain spaces around the '=' -RUN set -a && \\ +RUN set -a && \ . /app/.env && \ set +a && \ echo "Generating environment.prod.ts" && \ From 7d18e0a1bb23dbafb08e6a94267900d7677a6d26 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Tue, 19 Nov 2024 21:06:14 +0100 Subject: [PATCH 20/23] fix imprint centering --- webapp/src/app/legal/imprint/imprint.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapp/src/app/legal/imprint/imprint.component.ts b/webapp/src/app/legal/imprint/imprint.component.ts index ac058e05..1337b3d7 100644 --- a/webapp/src/app/legal/imprint/imprint.component.ts +++ b/webapp/src/app/legal/imprint/imprint.component.ts @@ -5,7 +5,7 @@ import { environment } from 'environments/environment'; selector: 'app-imprint', standalone: true, template: ` -
+

Imprint

From b79417bc63363a49cfd32a93f5df8f1eebb5c202 Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Wed, 20 Nov 2024 08:51:59 +0100 Subject: [PATCH 21/23] Fix: Parse Custom Date Range Query Params (#183) --- .../filter/timeframe/timeframe.component.html | 2 +- .../filter/timeframe/timeframe.component.ts | 35 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html index a5609498..c472dbf3 100644 --- a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html +++ b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.html @@ -8,7 +8,7 @@ Week starts {{ leaderboardSchedule().formatted }}
- + diff --git a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts index e69b7c0e..f479d877 100644 --- a/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts +++ b/webapp/src/app/home/leaderboard/filter/timeframe/timeframe.component.ts @@ -1,6 +1,6 @@ import { Component, computed, effect, inject, signal } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { Router } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import dayjs from 'dayjs'; import isoWeek from 'dayjs/plugin/isoWeek'; import { BrnSelectModule } from '@spartan-ng/ui-select-brain'; @@ -14,6 +14,7 @@ import { lucideHelpCircle } from '@ng-icons/lucide'; import { injectQuery } from '@tanstack/angular-query-experimental'; import { lastValueFrom } from 'rxjs'; import { MetaService } from '@app/core/modules/openapi'; +import { toSignal } from '@angular/core/rxjs-interop'; interface SelectOption { id: number; @@ -41,9 +42,8 @@ function formatLabel(weekIndex: number) { templateUrl: './timeframe.component.html' }) export class LeaderboardFilterTimeframeComponent { - after = signal(''); - before = signal(''); - value = signal(`${this.after()}.${this.before()}`); + private readonly route = inject(ActivatedRoute); + private queryParams = toSignal(this.route.queryParamMap, { requireSync: true }); metaService = inject(MetaService); dateQuery = injectQuery(() => ({ @@ -56,17 +56,22 @@ export class LeaderboardFilterTimeframeComponent { const timeParts = this.dateQuery.data()?.scheduledTime.split(':') ?? ['09', '00']; const hour = Number.parseInt(timeParts[0]); const minute = Number.parseInt(timeParts[1] ?? '0'); + const full = dayjs().isoWeekday(day).startOf('hour').hour(hour).minute(minute); return { day, hour, minute, - formatted: dayjs().isoWeekday(day).startOf('hour').hour(hour).minute(minute).format('dddd, h:mm A') + full, + formatted: full.format('dddd, h:mm A') }; }); + after = computed(() => this.queryParams().get('after') ?? (this.leaderboardSchedule() ? this.leaderboardSchedule().full.format() : '')); + before = computed(() => this.queryParams().get('before') ?? dayjs().format()); + selectValue = signal(`${this.after()}.${this.before()}`); + formattedDates = computed(() => { - const currentOption = this.value() !== '.' ? this.options().find((option) => option.value === this.value()) : this.options()[0]; - const [startDate, endDate] = currentOption!.value.split('.').map((date) => dayjs(date)); + const [startDate, endDate] = [dayjs(this.after()), dayjs(this.before())]; const sameMonth = startDate.month() === endDate.month(); const endDateFormatted = endDate.isSame(dayjs(), 'hour') ? 'Now' : sameMonth ? endDate.format('D, h:mm A') : endDate.format('MMM D, h:mm A'); if (sameMonth) { @@ -77,6 +82,9 @@ export class LeaderboardFilterTimeframeComponent { }); placeholder = computed(() => { + if (dayjs(this.after()).diff(this.before(), 'day') !== 7) { + return 'Custom range'; + } return formatLabel(dayjs(dayjs()).diff(this.after(), 'week')); }); @@ -108,19 +116,12 @@ export class LeaderboardFilterTimeframeComponent { }); constructor(private router: Router) { - // init params - const queryParams = this.router.parseUrl(this.router.url).queryParams; - this.after.set( - queryParams['after'] ?? dayjs().isoWeekday(this.leaderboardSchedule().day).startOf('hour').hour(this.leaderboardSchedule().hour).minute(this.leaderboardSchedule().minute) - ); - this.before.set(queryParams['before'] ?? dayjs().format()); - - // persist changes in url + // persist date changes in url effect(() => { - if (this.value().length === 1) return; + if (this.selectValue().length === 1) return; const queryParams = this.router.parseUrl(this.router.url).queryParams; - const dates = this.value().split('.'); + const dates = this.selectValue().split('.'); queryParams['after'] = dates[0]; queryParams['before'] = dates[1]; From 1222ea71858797672a2dd22b5b3a5c6331db6a6c Mon Sep 17 00:00:00 2001 From: Armin Stanitzok <21990230+GODrums@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:42:11 +0100 Subject: [PATCH 22/23] Show Parts of the Legend per default (#181) Co-authored-by: Felix T.J. Dietrich Co-authored-by: Felix T.J. Dietrich --- .../leaderboard/legend/legend.component.html | 62 +++++++++---------- .../leaderboard/legend/legends.component.ts | 32 ++++++---- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/webapp/src/app/home/leaderboard/legend/legend.component.html b/webapp/src/app/home/leaderboard/legend/legend.component.html index b3178176..5f8c8eea 100644 --- a/webapp/src/app/home/leaderboard/legend/legend.component.html +++ b/webapp/src/app/home/leaderboard/legend/legend.component.html @@ -1,20 +1,7 @@
-
-
-

Leaderboard Legend

-

Explanation of the most important elements

-
-
- @if (open()) { - - } @else { - - } -
-
-
+
-

Icons

+

Icons

Reviewed pull requests @@ -35,25 +22,32 @@

Icons

Code comments
-
-
-

Scoring System

-

- The score approximates your contribution activity by evaluating your review interactions and the complexity of the pull requests you've reviewed. - Change requests are valued highest, followed by approvals and comments. The score increases with the number of review interactions. Pull - request complexity — based on factors like changed files, commits, additions, and deletions — also enhances your score; - more complex pull requests contribute more. The final score balances your interactions with the complexity of the work reviewed, - highlighting both your engagement and the difficulty of the tasks you've undertaken. This score reflects your impact but does not directly measure time invested or work - quality. - - [source] - -

+
+
+ + +

+ The score approximates your contribution activity by evaluating your review interactions and the complexity of the pull requests you've reviewed. + Change requests are valued highest, followed by approvals and comments. The score increases with the number of review interactions. + Pull request complexity — based on factors like changed files, commits, additions, and deletions — also enhances your score; + more complex pull requests contribute more. The final score balances your interactions with the complexity of the work reviewed, + highlighting both your engagement and the difficulty of the tasks you've undertaken. This score reflects your impact but does not directly measure time invested or + work quality. + + [source] + +

+
+
+
diff --git a/webapp/src/app/home/leaderboard/legend/legends.component.ts b/webapp/src/app/home/leaderboard/legend/legends.component.ts index bc6da240..d25d87dc 100644 --- a/webapp/src/app/home/leaderboard/legend/legends.component.ts +++ b/webapp/src/app/home/leaderboard/legend/legends.component.ts @@ -1,18 +1,31 @@ -import { Component, computed, input, signal } from '@angular/core'; +import { Component, input } from '@angular/core'; import { NgIconComponent } from '@ng-icons/core'; import { octFileDiff, octCheck, octComment, octCommentDiscussion, octGitPullRequest } from '@ng-icons/octicons'; import { HlmIconComponent } from '@spartan-ng/ui-icon-helm'; import { HlmCardModule } from '@spartan-ng/ui-card-helm'; -import { provideIcons } from '@spartan-ng/ui-icon-helm'; -import { lucideChevronsDown, lucideChevronsUp } from '@ng-icons/lucide'; -import { cn } from '@app/utils'; import { HlmButtonDirective } from '@spartan-ng/ui-button-helm'; +import { + HlmAccordionContentComponent, + HlmAccordionDirective, + HlmAccordionIconDirective, + HlmAccordionItemDirective, + HlmAccordionTriggerDirective +} from '@spartan-ng/ui-accordion-helm'; @Component({ selector: 'app-leaderboard-legend', standalone: true, - imports: [HlmCardModule, NgIconComponent, HlmIconComponent, HlmButtonDirective], - providers: [provideIcons({ lucideChevronsDown, lucideChevronsUp })], + imports: [ + HlmAccordionDirective, + HlmAccordionItemDirective, + HlmAccordionTriggerDirective, + HlmAccordionContentComponent, + HlmAccordionIconDirective, + HlmCardModule, + NgIconComponent, + HlmIconComponent, + HlmButtonDirective + ], templateUrl: './legend.component.html' }) export class LeaderboardLegendComponent { @@ -23,11 +36,4 @@ export class LeaderboardLegendComponent { protected octGitPullRequest = octGitPullRequest; isLoading = input(); - open = signal(false); - - contentClass = computed(() => cn('flex flex-wrap gap-y-4 gap-x-8 pt-2', { hidden: !this.open() })); - - toggleOpen() { - this.open.set(!this.open()); - } } From 413105401a49cce018855b9b78382ac05c611841 Mon Sep 17 00:00:00 2001 From: "Felix T.J. Dietrich" Date: Wed, 20 Nov 2024 18:55:18 +0100 Subject: [PATCH 23/23] Add settings page to delete user (#182) --- ...cloak-hephaestus-realm-example-config.json | 4456 +++++++++-------- server/application-server/openapi.yaml | 8 + server/application-server/pom.xml | 5 + .../www1/hephaestus/OpenAPIConfiguration.java | 112 +- .../hephaestus/config/KeycloakConfig.java | 35 + .../gitprovider/user/UserController.java | 38 +- .../src/main/resources/application-prod.yml | 7 + .../src/main/resources/application.yml | 5 + webapp/src/app/app.routes.ts | 2 + .../src/app/core/header/header.component.html | 4 + .../src/app/core/header/header.component.ts | 5 +- .../core/modules/openapi/api/user.service.ts | 58 + .../openapi/api/user.serviceInterface.ts | 6 + webapp/src/app/settings/settings.component.ts | 71 + 14 files changed, 2696 insertions(+), 2116 deletions(-) create mode 100644 server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/KeycloakConfig.java create mode 100644 webapp/src/app/settings/settings.component.ts diff --git a/server/application-server/keycloak-hephaestus-realm-example-config.json b/server/application-server/keycloak-hephaestus-realm-example-config.json index 649340a4..dd795ec5 100644 --- a/server/application-server/keycloak-hephaestus-realm-example-config.json +++ b/server/application-server/keycloak-hephaestus-realm-example-config.json @@ -1,2086 +1,2394 @@ { - "id" : "69732d45-1431-4909-9335-9f39e304f823", - "realm" : "hephaestus", - "displayName" : "Hephaestus", - "displayNameHtml" : "", - "notBefore" : 0, - "defaultSignatureAlgorithm" : "RS256", - "revokeRefreshToken" : false, - "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, - "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, - "ssoSessionIdleTimeoutRememberMe" : 0, - "ssoSessionMaxLifespanRememberMe" : 0, - "offlineSessionIdleTimeout" : 2592000, - "offlineSessionMaxLifespanEnabled" : false, - "offlineSessionMaxLifespan" : 5184000, - "clientSessionIdleTimeout" : 0, - "clientSessionMaxLifespan" : 0, - "clientOfflineSessionIdleTimeout" : 0, - "clientOfflineSessionMaxLifespan" : 0, - "accessCodeLifespan" : 60, - "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, - "actionTokenGeneratedByAdminLifespan" : 43200, - "actionTokenGeneratedByUserLifespan" : 300, - "oauth2DeviceCodeLifespan" : 600, - "oauth2DevicePollingInterval" : 5, - "enabled" : true, - "sslRequired" : "external", - "registrationAllowed" : false, - "registrationEmailAsUsername" : false, - "rememberMe" : false, - "verifyEmail" : false, - "loginWithEmailAllowed" : false, - "duplicateEmailsAllowed" : false, - "resetPasswordAllowed" : false, - "editUsernameAllowed" : false, - "bruteForceProtected" : false, - "permanentLockout" : false, - "maxTemporaryLockouts" : 0, - "maxFailureWaitSeconds" : 900, - "minimumQuickLoginWaitSeconds" : 60, - "waitIncrementSeconds" : 60, - "quickLoginCheckMilliSeconds" : 1000, - "maxDeltaTimeSeconds" : 43200, - "failureFactor" : 30, - "roles" : { - "realm" : [ { - "id" : "2c84cd55-3b48-4e4a-8c4d-c94cf6ae0810", - "name" : "offline_access", - "description" : "${role_offline-access}", - "composite" : false, - "clientRole" : false, - "containerId" : "69732d45-1431-4909-9335-9f39e304f823", - "attributes" : { } - }, { - "id" : "97e10494-a59d-4d17-bf44-951411184167", - "name" : "default-roles-hephaestus", - "description" : "${role_default-roles}", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ], - "client" : { - "account" : [ "view-profile", "manage-account" ] + "id": "69732d45-1431-4909-9335-9f39e304f823", + "realm": "hephaestus", + "displayName": "Hephaestus", + "displayNameHtml": "", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": false, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxTemporaryLockouts": 0, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "2c84cd55-3b48-4e4a-8c4d-c94cf6ae0810", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "69732d45-1431-4909-9335-9f39e304f823", + "attributes": {} + }, + { + "id": "97e10494-a59d-4d17-bf44-951411184167", + "name": "default-roles-hephaestus", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": ["offline_access", "uma_authorization"], + "client": { + "account": ["view-profile", "manage-account"] + } + }, + "clientRole": false, + "containerId": "69732d45-1431-4909-9335-9f39e304f823", + "attributes": {} + }, + { + "id": "a0bcdf44-1bd1-4b3d-8667-021f2bc8802b", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "69732d45-1431-4909-9335-9f39e304f823", + "attributes": {} + }, + { + "id": "4343b5c5-a9c1-4f09-a288-985a1e9600b7", + "name": "admin", + "description": "", + "composite": false, + "clientRole": false, + "containerId": "69732d45-1431-4909-9335-9f39e304f823", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "5d39be32-4468-482f-a91d-9fbe22248742", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "652c45f7-cebe-4359-b5b7-b4f3e28d0d14", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "6e9e7f1e-f494-48af-80da-182de15e5c5a", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "28493c88-62eb-426c-ad10-89aa77b79d0c", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "2c40b71c-0827-4667-b03a-3049213fd6fe", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "4aed2108-69c8-48de-b042-5650341fe86a", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "e78b4671-3cc1-4e95-84a2-f829d081ac8e", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "manage-clients", + "manage-realm", + "impersonation", + "create-client", + "view-realm", + "query-clients", + "view-users", + "view-identity-providers", + "manage-events", + "view-events", + "manage-identity-providers", + "query-users", + "view-clients", + "manage-users", + "view-authorization", + "query-groups", + "query-realms", + "manage-authorization" + ] + } + }, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "6a701450-c66f-4ba3-b217-ce42127fd097", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "3e633de5-5f4c-4005-a33c-efaf44491cb5", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "102f5f2d-7e29-46f8-91b1-d90446faaf18", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-users", "query-groups"] + } + }, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "54b2f7ef-a129-4e33-86f8-76bb0ca751ce", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "19e94593-ce41-42e2-84da-2d2c03f7eab8", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "d82cc9d1-21ab-41ed-aba1-18940def7769", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "c2340cff-48e7-424e-9bee-1d0e8c1f55db", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "c3664c6a-0061-49f9-8fb4-0bef297e25f6", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-clients"] + } + }, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "918a71ab-4a8e-4c79-a41a-c6d6bcd227c4", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "4154b55a-5877-4d62-af2f-dba98caa0b26", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "116dc63e-b8dd-47c5-a2a1-0cbf5bd3437f", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + }, + { + "id": "70f66368-a626-45b6-a900-880fbc782edf", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "attributes": {} + } + ], + "hephaestus": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "5c040740-eadb-454c-ad1a-fbccb0dc6c13", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "bac35493-ce58-4842-b70d-6322d2838f7e", + "attributes": {} + } + ], + "hephaestus-confidential": [ + { + "id": "aeabd04b-145b-4a89-8fca-b90cb8e27f53", + "name": "realm-admin", + "description": "", + "composite": true, + "composites": { + "client": { + "realm-management": ["manage-users"] + } + }, + "clientRole": true, + "containerId": "a0b56844-28ca-4134-91c3-99247ad6e2cf", + "attributes": {} + } + ], + "account": [ + { + "id": "7c46f836-e0b4-4635-9954-d615645beb0d", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": ["view-consent"] + } + }, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "a941a94c-7bd5-4604-b23d-df6cea6dfab7", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "d8fb1923-8b74-4d38-826e-6e02355c7527", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "c00e6853-205d-41f7-a178-bc6ee2d0a1b4", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "e016406e-12ba-4a2f-82bf-fc60fdbe2c0b", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "b0ddf57b-dede-4263-a917-9deef86bc93b", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "497eca79-c59f-4a67-b447-a9d75903973e", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + }, + { + "id": "8f650738-fc6e-42c4-846a-5d940fbc5f2f", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": ["manage-account-links"] + } + }, + "clientRole": true, + "containerId": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "attributes": {} + } + ] } - }, - "clientRole" : false, - "containerId" : "69732d45-1431-4909-9335-9f39e304f823", - "attributes" : { } - }, { - "id" : "a0bcdf44-1bd1-4b3d-8667-021f2bc8802b", - "name" : "uma_authorization", - "description" : "${role_uma_authorization}", - "composite" : false, - "clientRole" : false, - "containerId" : "69732d45-1431-4909-9335-9f39e304f823", - "attributes" : { } - }, { - "id" : "4343b5c5-a9c1-4f09-a288-985a1e9600b7", - "name" : "admin", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "69732d45-1431-4909-9335-9f39e304f823", - "attributes" : { } - } ], - "client" : { - "realm-management" : [ { - "id" : "5d39be32-4468-482f-a91d-9fbe22248742", - "name" : "manage-clients", - "description" : "${role_manage-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "652c45f7-cebe-4359-b5b7-b4f3e28d0d14", - "name" : "manage-realm", - "description" : "${role_manage-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "6e9e7f1e-f494-48af-80da-182de15e5c5a", - "name" : "impersonation", - "description" : "${role_impersonation}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "28493c88-62eb-426c-ad10-89aa77b79d0c", - "name" : "create-client", - "description" : "${role_create-client}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "2c40b71c-0827-4667-b03a-3049213fd6fe", - "name" : "view-realm", - "description" : "${role_view-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "4aed2108-69c8-48de-b042-5650341fe86a", - "name" : "query-clients", - "description" : "${role_query-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "e78b4671-3cc1-4e95-84a2-f829d081ac8e", - "name" : "realm-admin", - "description" : "${role_realm-admin}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "manage-realm", "manage-clients", "impersonation", "create-client", "view-realm", "query-clients", "view-users", "view-identity-providers", "manage-events", "view-events", "manage-identity-providers", "view-clients", "manage-users", "query-users", "view-authorization", "query-groups", "query-realms", "manage-authorization" ] - } + }, + "groups": [], + "defaultRole": { + "id": "97e10494-a59d-4d17-bf44-951411184167", + "name": "default-roles-hephaestus", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "69732d45-1431-4909-9335-9f39e304f823" + }, + "requiredCredentials": ["password"], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": ["totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName"], + "localizationTexts": {}, + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyExtraOrigins": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256", "RS256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "webAuthnPolicyPasswordlessExtraOrigins": [], + "users": [ + { + "id": "9512503b-98f9-4acc-8b7d-59214034d579", + "username": "service-account-hephaestus-confidential", + "emailVerified": false, + "createdTimestamp": 1732055412681, + "enabled": true, + "totp": false, + "serviceAccountClientId": "hephaestus-confidential", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": ["default-roles-hephaestus"], + "clientRoles": { + "realm-management": ["manage-users", "realm-admin"] + }, + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": ["offline_access"] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account", "view-groups"] + } + ] + }, + "clients": [ + { + "id": "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/hephaestus/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/hephaestus/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "6a701450-c66f-4ba3-b217-ce42127fd097", - "name" : "manage-events", - "description" : "${role_manage-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "3e633de5-5f4c-4005-a33c-efaf44491cb5", - "name" : "view-identity-providers", - "description" : "${role_view-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "102f5f2d-7e29-46f8-91b1-d90446faaf18", - "name" : "view-users", - "description" : "${role_view-users}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-users", "query-groups" ] - } + { + "id": "f535e2e7-cf8a-458f-b702-8f4fc81ded81", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/hephaestus/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/hephaestus/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "c0935091-06a4-464c-a768-cf15ea43182c", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "54b2f7ef-a129-4e33-86f8-76bb0ca751ce", - "name" : "view-events", - "description" : "${role_view-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "19e94593-ce41-42e2-84da-2d2c03f7eab8", - "name" : "manage-identity-providers", - "description" : "${role_manage-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "d82cc9d1-21ab-41ed-aba1-18940def7769", - "name" : "manage-users", - "description" : "${role_manage-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "c2340cff-48e7-424e-9bee-1d0e8c1f55db", - "name" : "query-users", - "description" : "${role_query-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "c3664c6a-0061-49f9-8fb4-0bef297e25f6", - "name" : "view-clients", - "description" : "${role_view-clients}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-clients" ] - } + { + "id": "13a66738-5ffc-417d-93c0-ea14dafba95f", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "918a71ab-4a8e-4c79-a41a-c6d6bcd227c4", - "name" : "query-groups", - "description" : "${role_query-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "4154b55a-5877-4d62-af2f-dba98caa0b26", - "name" : "view-authorization", - "description" : "${role_view-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "116dc63e-b8dd-47c5-a2a1-0cbf5bd3437f", - "name" : "query-realms", - "description" : "${role_query-realms}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - }, { - "id" : "70f66368-a626-45b6-a900-880fbc782edf", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "attributes" : { } - } ], - "hephaestus" : [ ], - "security-admin-console" : [ ], - "admin-cli" : [ ], - "account-console" : [ ], - "broker" : [ { - "id" : "5c040740-eadb-454c-ad1a-fbccb0dc6c13", - "name" : "read-token", - "description" : "${role_read-token}", - "composite" : false, - "clientRole" : true, - "containerId" : "bac35493-ce58-4842-b70d-6322d2838f7e", - "attributes" : { } - } ], - "hephaestus-confidential" : [ ], - "account" : [ { - "id" : "7c46f836-e0b4-4635-9954-d615645beb0d", - "name" : "manage-consent", - "description" : "${role_manage-consent}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "view-consent" ] - } + { + "id": "bac35493-ce58-4842-b70d-6322d2838f7e", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "a941a94c-7bd5-4604-b23d-df6cea6dfab7", - "name" : "manage-account-links", - "description" : "${role_manage-account-links}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "d8fb1923-8b74-4d38-826e-6e02355c7527", - "name" : "view-applications", - "description" : "${role_view-applications}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "c00e6853-205d-41f7-a178-bc6ee2d0a1b4", - "name" : "view-groups", - "description" : "${role_view-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "e016406e-12ba-4a2f-82bf-fc60fdbe2c0b", - "name" : "delete-account", - "description" : "${role_delete-account}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "b0ddf57b-dede-4263-a917-9deef86bc93b", - "name" : "view-profile", - "description" : "${role_view-profile}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "497eca79-c59f-4a67-b447-a9d75903973e", - "name" : "view-consent", - "description" : "${role_view-consent}", - "composite" : false, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - }, { - "id" : "8f650738-fc6e-42c4-846a-5d940fbc5f2f", - "name" : "manage-account", - "description" : "${role_manage-account}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "manage-account-links" ] - } + { + "id": "e252b764-192f-46e8-a16a-b5bd711d9562", + "clientId": "hephaestus", + "name": "", + "description": "", + "rootUrl": "http://localhost:4200", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["http://localhost:4200/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "http://localhost:4200/*", + "display.on.consent.screen": "false", + "oauth2.device.authorization.grant.enabled": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] }, - "clientRole" : true, - "containerId" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "attributes" : { } - } ] - } - }, - "groups" : [ ], - "defaultRole" : { - "id" : "97e10494-a59d-4d17-bf44-951411184167", - "name" : "default-roles-hephaestus", - "description" : "${role_default-roles}", - "composite" : true, - "clientRole" : false, - "containerId" : "69732d45-1431-4909-9335-9f39e304f823" - }, - "requiredCredentials" : [ "password" ], - "otpPolicyType" : "totp", - "otpPolicyAlgorithm" : "HmacSHA1", - "otpPolicyInitialCounter" : 0, - "otpPolicyDigits" : 6, - "otpPolicyLookAheadWindow" : 1, - "otpPolicyPeriod" : 30, - "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], - "localizationTexts" : { }, - "webAuthnPolicyRpEntityName" : "keycloak", - "webAuthnPolicySignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyRpId" : "", - "webAuthnPolicyAttestationConveyancePreference" : "not specified", - "webAuthnPolicyAuthenticatorAttachment" : "not specified", - "webAuthnPolicyRequireResidentKey" : "not specified", - "webAuthnPolicyUserVerificationRequirement" : "not specified", - "webAuthnPolicyCreateTimeout" : 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyAcceptableAaguids" : [ ], - "webAuthnPolicyExtraOrigins" : [ ], - "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256", "RS256" ], - "webAuthnPolicyPasswordlessRpId" : "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", - "webAuthnPolicyPasswordlessCreateTimeout" : 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], - "webAuthnPolicyPasswordlessExtraOrigins" : [ ], - "users" : [ { - "id" : "9d394368-150d-4559-b005-758a50cbb353", - "username" : "admin", - "firstName" : "Admin", - "lastName" : "Heph", - "email" : "admin@test.de", - "emailVerified" : true, - "createdTimestamp" : 1728164083186, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "3da23015-0fac-48c2-a8e3-eeb716b61191", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1728164095322, - "secretData" : "{\"value\":\"BTbtjHu/bRIKqfSJhKGphtBmss3tMTulJbyEliEtauA=\",\"salt\":\"T5PabTudL9XbW/hfyARmSw==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-hephaestus", "admin" ], - "notBefore" : 0, - "groups" : [ ] - }, { - "id" : "6089efcd-06c1-4688-b23f-992871bfc299", - "username" : "testuser", - "firstName" : "Test", - "lastName" : "User", - "email" : "testuser@test.de", - "emailVerified" : false, - "createdTimestamp" : 1728164130587, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "d29517ce-b1cf-4058-b851-33c5364fff21", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1728164143708, - "secretData" : "{\"value\":\"CaelkV+Qy8IH8fV6kG97jePGwsnUpTNzRkxdfKb+IuY=\",\"salt\":\"4UtFbmsnpzl+YS7CwCuZDA==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-hephaestus" ], - "notBefore" : 0, - "groups" : [ ] - } ], - "scopeMappings" : [ { - "clientScope" : "offline_access", - "roles" : [ "offline_access" ] - } ], - "clientScopeMappings" : { - "account" : [ { - "client" : "account-console", - "roles" : [ "manage-account", "view-groups" ] - } ] - }, - "clients" : [ { - "id" : "e056b5cf-5a9e-4f1e-9070-5b718f99bd10", - "clientId" : "account", - "name" : "${client_account}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/hephaestus/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/hephaestus/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "f535e2e7-cf8a-458f-b702-8f4fc81ded81", - "clientId" : "account-console", - "name" : "${client_account-console}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/hephaestus/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/hephaestus/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "c0935091-06a4-464c-a768-cf15ea43182c", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "13a66738-5ffc-417d-93c0-ea14dafba95f", - "clientId" : "admin-cli", - "name" : "${client_admin-cli}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : false, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "bac35493-ce58-4842-b70d-6322d2838f7e", - "clientId" : "broker", - "name" : "${client_broker}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "e252b764-192f-46e8-a16a-b5bd711d9562", - "clientId" : "hephaestus", - "name" : "", - "description" : "", - "rootUrl" : "http://localhost:4200", - "adminUrl" : "", - "baseUrl" : "", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "http://localhost:4200/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : true, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "oidc.ciba.grant.enabled" : "false", - "backchannel.logout.session.required" : "true", - "post.logout.redirect.uris" : "http://localhost:4200/*", - "display.on.consent.screen" : "false", - "oauth2.device.authorization.grant.enabled" : "false", - "backchannel.logout.revoke.offline.tokens" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "a0b56844-28ca-4134-91c3-99247ad6e2cf", - "clientId" : "hephaestus-confidential", - "name" : "", - "description" : "", - "rootUrl" : "http://localhost:8080", - "adminUrl" : "http://localhost:8080", - "baseUrl" : "http://localhost:8080/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "0g0QtFmz6GB1Jv03SszCFepPro0hiP7G", - "redirectUris" : [ "http://localhost:8080/login/oauth2/code/keycloak" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : true, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "oidc.ciba.grant.enabled" : "false", - "client.secret.creation.time" : "1728160951", - "backchannel.logout.session.required" : "true", - "post.logout.redirect.uris" : "http://localhost:8080/", - "display.on.consent.screen" : "false", - "oauth2.device.authorization.grant.enabled" : "false", - "use.jwks.url" : "false", - "backchannel.logout.revoke.offline.tokens" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "5efe8644-a9eb-4fec-8293-b586b56bbeb2", - "clientId" : "realm-management", - "name" : "${client_realm-management}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "true" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - }, { - "id" : "7b12cc2f-fe73-4987-8151-a610a3c966c7", - "clientId" : "security-admin-console", - "name" : "${client_security-admin-console}", - "rootUrl" : "${authAdminUrl}", - "baseUrl" : "/admin/hephaestus/console/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/admin/hephaestus/console/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "realm_client" : "false", - "client.use.lightweight.access.token.enabled" : "true", - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "58d3f8f1-39b1-4636-93de-a1a6ffdcb47c", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "organization", "microprofile-jwt" ] - } ], - "clientScopes" : [ { - "id" : "79c7da3a-81a6-452a-b4cc-2d3a8b4e80f6", - "name" : "profile", - "description" : "OpenID Connect built-in scope: profile", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${profileScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "6cbe8cae-c58f-4da1-8445-8dab4bd94966", - "name" : "profile", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "profile", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "profile", - "jsonType.label" : "String" - } - }, { - "id" : "9406ae58-c99e-4080-ac8b-3d99dcfa2383", - "name" : "zoneinfo", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "zoneinfo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "zoneinfo", - "jsonType.label" : "String" - } - }, { - "id" : "c9c6c0e3-4fab-4d3e-a589-baad4a9860fb", - "name" : "birthdate", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "birthdate", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "birthdate", - "jsonType.label" : "String" - } - }, { - "id" : "b2476817-0946-4cba-a50f-383fd95252db", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String" - } - }, { - "id" : "222eb11d-14bf-4d18-9b4f-ebe60e71d29e", - "name" : "website", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "website", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "website", - "jsonType.label" : "String" - } - }, { - "id" : "bf484a0e-11ee-43e0-a240-55901d47ffb7", - "name" : "nickname", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "nickname", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "nickname", - "jsonType.label" : "String" - } - }, { - "id" : "482ace7f-c063-483d-8788-25fa45bacbb4", - "name" : "middle name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "middleName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "middle_name", - "jsonType.label" : "String" - } - }, { - "id" : "98f6a432-5ce5-4cf5-b99e-5ecf50424f41", - "name" : "updated at", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "updatedAt", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "updated_at", - "jsonType.label" : "long" - } - }, { - "id" : "fa3d4a1b-a835-48e1-ac3a-19dbf6f732ee", - "name" : "username", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "preferred_username", - "jsonType.label" : "String" - } - }, { - "id" : "803eac69-2d9d-43e8-a5b5-f93369440ff5", - "name" : "given name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "firstName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "given_name", - "jsonType.label" : "String" - } - }, { - "id" : "f934033c-e042-414b-8ffc-d20363467595", - "name" : "family name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "lastName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "family_name", - "jsonType.label" : "String" - } - }, { - "id" : "90916393-5fa4-45f4-9b33-1c4fa246f0d0", - "name" : "picture", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "picture", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "picture", - "jsonType.label" : "String" - } - }, { - "id" : "dd127c7c-cc1d-4986-91d2-e35298a9188d", - "name" : "gender", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "gender", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "gender", - "jsonType.label" : "String" - } - }, { - "id" : "9f997d51-8ce7-4d24-afcc-23054e68f083", - "name" : "full name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-full-name-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "userinfo.token.claim" : "true" - } - } ] - }, { - "id" : "8ae11c15-2b57-4376-81c9-5178ca01141d", - "name" : "email", - "description" : "OpenID Connect built-in scope: email", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${emailScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "2a8fcde0-c6e2-4f4f-9120-24c3236b1feb", - "name" : "email verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "emailVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email_verified", - "jsonType.label" : "boolean" - } - }, { - "id" : "74a748aa-7333-4590-9b26-81a98f12addd", - "name" : "email", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "email", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "4d196069-3b93-47c3-bb58-225541755f1a", - "name" : "acr", - "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "49a28a8b-89a4-44d3-9124-06d6f1d6ac84", - "name" : "acr loa level", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-acr-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "3bf3dd35-3667-4ed9-a5fc-b385b8bccced", - "name" : "offline_access", - "description" : "OpenID Connect built-in scope: offline_access", - "protocol" : "openid-connect", - "attributes" : { - "consent.screen.text" : "${offlineAccessScopeConsentText}", - "display.on.consent.screen" : "true" - } - }, { - "id" : "772189c7-99ab-4217-8b8a-1a2f904d571e", - "name" : "basic", - "description" : "OpenID Connect scope for add all basic claims to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "0d72f910-b47e-435e-85cd-97a4c513ea55", - "name" : "auth_time", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "AUTH_TIME", - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "auth_time", - "jsonType.label" : "long" - } - }, { - "id" : "1bc4aa92-2849-45d6-a460-09aca7fb68c6", - "name" : "sub", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-sub-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "41d27626-b651-4298-b9ec-5a6fb170f7e2", - "name" : "web-origins", - "description" : "OpenID Connect scope for add allowed web origins to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "e3bfb3b9-8f0e-47ef-a348-dedf2339b6a3", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "911c8968-b150-47e0-9bc9-46faf6a824e3", - "name" : "address", - "description" : "OpenID Connect built-in scope: address", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${addressScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "9578f861-b6af-4355-96e5-033048ae902f", - "name" : "address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-address-mapper", - "consentRequired" : false, - "config" : { - "user.attribute.formatted" : "formatted", - "user.attribute.country" : "country", - "introspection.token.claim" : "true", - "user.attribute.postal_code" : "postal_code", - "userinfo.token.claim" : "true", - "user.attribute.street" : "street", - "id.token.claim" : "true", - "user.attribute.region" : "region", - "access.token.claim" : "true", - "user.attribute.locality" : "locality" - } - } ] - }, { - "id" : "835e378e-fc46-4630-8330-cb6b0b3b41d8", - "name" : "phone", - "description" : "OpenID Connect built-in scope: phone", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${phoneScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "1c87e0d2-927d-4a13-8e2c-b2ef9fb90e1e", - "name" : "phone number verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumberVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" - } - }, { - "id" : "684e356f-6678-48f3-bf14-2fc6c588ae35", - "name" : "phone number", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "phoneNumber", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number", - "jsonType.label" : "String" - } - } ] - }, { - "id" : "37d66c21-8e27-477a-a375-104e3c24dc3a", - "name" : "organization", - "description" : "Additional claims about the organization a subject belongs to", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${organizationScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "5db0eef8-66b0-41f8-b8e8-492a8deccc92", - "name" : "organization", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-organization-membership-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "organization", - "jsonType.label" : "String", - "multivalued" : "true" - } - } ] - }, { - "id" : "6b5aa1ab-aa2a-4e54-8305-19625d8302c5", - "name" : "role_list", - "description" : "SAML role list", - "protocol" : "saml", - "attributes" : { - "consent.screen.text" : "${samlRoleListScopeConsentText}", - "display.on.consent.screen" : "true" + { + "id": "a0b56844-28ca-4134-91c3-99247ad6e2cf", + "clientId": "hephaestus-confidential", + "name": "", + "description": "", + "rootUrl": "http://localhost:8080", + "adminUrl": "http://localhost:8080", + "baseUrl": "http://localhost:8080/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "0g0QtFmz6GB1Jv03SszCFepPro0hiP7G", + "redirectUris": ["http://localhost:8080/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "oidc.ciba.grant.enabled": "false", + "client.secret.creation.time": "1728160951", + "backchannel.logout.session.required": "true", + "post.logout.redirect.uris": "http://localhost:8080/", + "display.on.consent.screen": "false", + "oauth2.device.authorization.grant.enabled": "false", + "use.jwks.url": "false", + "backchannel.logout.revoke.offline.tokens": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "184aca95-d1f4-4369-a076-6db0ebcf0e48", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "980073f4-9de7-4bf7-ac68-dc0484854b94", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "client_id", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "client_id", + "jsonType.label": "String" + } + }, + { + "id": "5fe7cc96-5ca4-4f25-ac48-30fd3d7c1446", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + }, + { + "id": "5efe8644-a9eb-4fec-8293-b586b56bbeb2", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "true", + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + }, + { + "id": "7b12cc2f-fe73-4987-8151-a610a3c966c7", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/hephaestus/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/admin/hephaestus/console/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "realm_client": "false", + "client.use.lightweight.access.token.enabled": "true", + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "58d3f8f1-39b1-4636-93de-a1a6ffdcb47c", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": ["web-origins", "acr", "profile", "roles", "basic", "email"], + "optionalClientScopes": ["address", "phone", "offline_access", "organization", "microprofile-jwt"] + } + ], + "clientScopes": [ + { + "id": "79c7da3a-81a6-452a-b4cc-2d3a8b4e80f6", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${profileScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "6cbe8cae-c58f-4da1-8445-8dab4bd94966", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "9406ae58-c99e-4080-ac8b-3d99dcfa2383", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "c9c6c0e3-4fab-4d3e-a589-baad4a9860fb", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "b2476817-0946-4cba-a50f-383fd95252db", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "222eb11d-14bf-4d18-9b4f-ebe60e71d29e", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "bf484a0e-11ee-43e0-a240-55901d47ffb7", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "482ace7f-c063-483d-8788-25fa45bacbb4", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "98f6a432-5ce5-4cf5-b99e-5ecf50424f41", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "fa3d4a1b-a835-48e1-ac3a-19dbf6f732ee", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "803eac69-2d9d-43e8-a5b5-f93369440ff5", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "f934033c-e042-414b-8ffc-d20363467595", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "90916393-5fa4-45f4-9b33-1c4fa246f0d0", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "dd127c7c-cc1d-4986-91d2-e35298a9188d", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "9f997d51-8ce7-4d24-afcc-23054e68f083", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "8ae11c15-2b57-4376-81c9-5178ca01141d", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${emailScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "2a8fcde0-c6e2-4f4f-9120-24c3236b1feb", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "74a748aa-7333-4590-9b26-81a98f12addd", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "4d196069-3b93-47c3-bb58-225541755f1a", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "49a28a8b-89a4-44d3-9124-06d6f1d6ac84", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "3bf3dd35-3667-4ed9-a5fc-b385b8bccced", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "772189c7-99ab-4217-8b8a-1a2f904d571e", + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "0d72f910-b47e-435e-85cd-97a4c513ea55", + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + }, + { + "id": "1bc4aa92-2849-45d6-a460-09aca7fb68c6", + "name": "sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-sub-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "41d27626-b651-4298-b9ec-5a6fb170f7e2", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "e3bfb3b9-8f0e-47ef-a348-dedf2339b6a3", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "911c8968-b150-47e0-9bc9-46faf6a824e3", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${addressScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "9578f861-b6af-4355-96e5-033048ae902f", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "introspection.token.claim": "true", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "835e378e-fc46-4630-8330-cb6b0b3b41d8", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${phoneScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "1c87e0d2-927d-4a13-8e2c-b2ef9fb90e1e", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "684e356f-6678-48f3-bf14-2fc6c588ae35", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "37d66c21-8e27-477a-a375-104e3c24dc3a", + "name": "organization", + "description": "Additional claims about the organization a subject belongs to", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "consent.screen.text": "${organizationScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "5db0eef8-66b0-41f8-b8e8-492a8deccc92", + "name": "organization", + "protocol": "openid-connect", + "protocolMapper": "oidc-organization-membership-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "organization", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "6b5aa1ab-aa2a-4e54-8305-19625d8302c5", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "89115602-84e7-4527-a7c6-e9068626dd75", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "0da153bc-c512-4291-8ecb-9e4d2f04e84a", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "consent.screen.text": "${rolesScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "18e94f40-5433-4258-890a-d210b34bef43", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "c8ea1e27-1eb3-4179-a5ba-3888de80791b", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "introspection.token.claim": "true", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "43da0b25-27ce-480c-a8d8-eb96e2a1aac6", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "id": "02ec6185-0610-45cd-b7c8-765736164389", + "name": "saml_organization", + "description": "Organization Membership", + "protocol": "saml", + "attributes": { + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "9b84b9d6-7f7f-43fa-aef3-11cf08a24751", + "name": "organization", + "protocol": "saml", + "protocolMapper": "saml-organization-membership-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "88df9ce0-d2f4-4290-8f3c-4bdf701935d3", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "eb7ea7aa-740a-447c-b4d2-bac5f799e885", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "dc1fa0ab-686f-4068-b164-d1c9fff45e05", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "saml_organization", + "profile", + "email", + "roles", + "web-origins", + "acr", + "basic" + ], + "defaultOptionalClientScopes": ["offline_access", "address", "phone", "microprofile-jwt", "organization"], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "referrerPolicy": "no-referrer", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" }, - "protocolMappers" : [ { - "id" : "89115602-84e7-4527-a7c6-e9068626dd75", - "name" : "role list", - "protocol" : "saml", - "protocolMapper" : "saml-role-list-mapper", - "consentRequired" : false, - "config" : { - "single" : "false", - "attribute.nameformat" : "Basic", - "attribute.name" : "Role" - } - } ] - }, { - "id" : "0da153bc-c512-4291-8ecb-9e4d2f04e84a", - "name" : "roles", - "description" : "OpenID Connect scope for add user roles to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "${rolesScopeConsentText}", - "display.on.consent.screen" : "true" + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": ["jboss-logging"], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "16fe477e-8a5a-4380-a5eb-7745eec891b4", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "a033bc0d-09d6-419a-bfc0-d4995481776f", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": ["true"], + "client-uris-must-match": ["true"] + } + }, + { + "id": "3c2dd507-9e0d-4e5e-b4cc-e82b5293ae98", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "8b889e60-dc84-4f14-a2ba-147fa6a4cce8", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "a502be67-07d2-4923-a2bd-e52c41e65e2c", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "968fe0a6-8f46-4d5b-9206-d8713996165a", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "18382a69-ff16-46a3-ad34-01fa7b96cb93", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "4eb21c3a-e868-4f12-9faa-c498903f8b58", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": ["200"] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "6447c1d0-4b09-4140-848b-ec14db7531b4", + "name": "hmac-generated-hs512", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": ["100"], + "algorithm": ["HS512"] + } + }, + { + "id": "d89fd5f0-2406-4ec4-b617-562870a59547", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": ["100"], + "algorithm": ["RSA-OAEP"] + } + }, + { + "id": "d9ce5a63-3167-4216-a290-ffa39975a506", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": ["100"] + } + }, + { + "id": "cc996409-8e41-4671-b18b-8d4255fd30d0", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": ["100"] + } + } + ] }, - "protocolMappers" : [ { - "id" : "18e94f40-5433-4258-890a-d210b34bef43", - "name" : "client roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-client-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "c8ea1e27-1eb3-4179-a5ba-3888de80791b", - "name" : "realm roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "introspection.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "43da0b25-27ce-480c-a8d8-eb96e2a1aac6", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "02ec6185-0610-45cd-b7c8-765736164389", - "name" : "saml_organization", - "description" : "Organization Membership", - "protocol" : "saml", - "attributes" : { - "display.on.consent.screen" : "false" + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "f85d840f-75c3-4df4-ae43-0501b35e3000", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "fdd5bf34-07a2-4f7f-a27b-607316c1cdc9", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "5fe895b4-993d-4a89-9d08-f4e9898c67f6", + "alias": "Browser - Conditional Organization", + "description": "Flow to determine if the organization identity-first login is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "organization", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "500616bb-c431-4096-a49e-0df1ef41cff5", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "4607238a-087e-4403-905d-3833ab84002b", + "alias": "First Broker Login - Conditional Organization", + "description": "Flow to determine if the authenticator that adds organization members is to be used", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "idp-add-organization-member", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "643831d9-db9a-464d-a9b1-ccc3effac995", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "ee88c7af-8c55-42ab-9469-5715fa035705", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "47788773-ba07-46ad-9d5b-5d28434db7d0", + "alias": "Organization", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "9b885aa9-5f5d-4e9f-b433-4c5ccbee1011", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8abdbd0c-81db-42a2-a7e4-dc48b5a93230", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "f21b5b62-8026-409e-b520-a81589b6b506", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "cf9f8864-670f-4067-9242-146f6660c603", + "alias": "browser", + "description": "Browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 26, + "autheticatorFlow": true, + "flowAlias": "Organization", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "ad9e7782-cd6b-4250-87ca-be3b841e7c3f", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "7781a9a1-f376-4755-b91c-aab751a0f884", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "c554d494-b117-4a66-97b7-1ac09fb14442", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "dd085248-fef6-41cb-8a5a-4826a4f3522e", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 50, + "autheticatorFlow": true, + "flowAlias": "First Broker Login - Conditional Organization", + "userSetupAllowed": false + } + ] + }, + { + "id": "215253c4-d9f1-4ca6-8bbf-70da1323832f", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "7319086a-99d5-474a-ab8f-9d908ad8dd18", + "alias": "registration", + "description": "Registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "0e642b52-d4b8-483c-835f-5d4b9ff89dda", + "alias": "registration form", + "description": "Registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-terms-and-conditions", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 70, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "62dcd4c7-c2d7-4b18-9ff2-d383eb1239ab", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "49b8c4ba-4385-4773-ab75-3229ab9d309e", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "bd1ac3c1-5c3a-493a-abc1-0f31269f372c", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "3d23706b-e877-4f86-88ab-1587a3642dbd", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "TERMS_AND_CONDITIONS", + "name": "Terms and Conditions", + "providerId": "TERMS_AND_CONDITIONS", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "VERIFY_PROFILE", + "name": "Verify Profile", + "providerId": "VERIFY_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 90, + "config": {} + }, + { + "alias": "delete_credential", + "name": "Delete Credential", + "providerId": "delete_credential", + "enabled": true, + "defaultAction": false, + "priority": 100, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "firstBrokerLoginFlow": "first broker login", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaAuthRequestedUserHint": "login_hint", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false", + "cibaExpiresIn": "120", + "oauth2DeviceCodeLifespan": "600", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "frontendUrl": "", + "organizationsEnabled": "false", + "acr.loa.map": "{}" }, - "protocolMappers" : [ { - "id" : "9b84b9d6-7f7f-43fa-aef3-11cf08a24751", - "name" : "organization", - "protocol" : "saml", - "protocolMapper" : "saml-organization-membership-mapper", - "consentRequired" : false, - "config" : { } - } ] - }, { - "id" : "88df9ce0-d2f4-4290-8f3c-4bdf701935d3", - "name" : "microprofile-jwt", - "description" : "Microprofile - JWT built-in scope", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "false" + "keycloakVersion": "26.0.0", + "userManagedAccessAllowed": false, + "organizationsEnabled": false, + "clientProfiles": { + "profiles": [] }, - "protocolMappers" : [ { - "id" : "eb7ea7aa-740a-447c-b4d2-bac5f799e885", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", - "user.attribute" : "foo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "groups", - "jsonType.label" : "String" - } - }, { - "id" : "dc1fa0ab-686f-4068-b164-d1c9fff45e05", - "name" : "upn", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "upn", - "jsonType.label" : "String" - } - } ] - } ], - "defaultDefaultClientScopes" : [ "role_list", "saml_organization", "profile", "email", "roles", "web-origins", "acr", "basic" ], - "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt", "organization" ], - "browserSecurityHeaders" : { - "contentSecurityPolicyReportOnly" : "", - "xContentTypeOptions" : "nosniff", - "referrerPolicy" : "no-referrer", - "xRobotsTag" : "none", - "xFrameOptions" : "SAMEORIGIN", - "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection" : "1; mode=block", - "strictTransportSecurity" : "max-age=31536000; includeSubDomains" - }, - "smtpServer" : { }, - "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], - "enabledEventTypes" : [ ], - "adminEventsEnabled" : false, - "adminEventsDetailsEnabled" : false, - "identityProviders" : [ ], - "identityProviderMappers" : [ ], - "components" : { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { - "id" : "16fe477e-8a5a-4380-a5eb-7745eec891b4", - "name" : "Consent Required", - "providerId" : "consent-required", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "a033bc0d-09d6-419a-bfc0-d4995481776f", - "name" : "Trusted Hosts", - "providerId" : "trusted-hosts", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "host-sending-registration-request-must-match" : [ "true" ], - "client-uris-must-match" : [ "true" ] - } - }, { - "id" : "3c2dd507-9e0d-4e5e-b4cc-e82b5293ae98", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "8b889e60-dc84-4f14-a2ba-147fa6a4cce8", - "name" : "Full Scope Disabled", - "providerId" : "scope", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "a502be67-07d2-4923-a2bd-e52c41e65e2c", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "968fe0a6-8f46-4d5b-9206-d8713996165a", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-property-mapper" ] - } - }, { - "id" : "18382a69-ff16-46a3-ad34-01fa7b96cb93", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-address-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-attribute-mapper" ] - } - }, { - "id" : "4eb21c3a-e868-4f12-9faa-c498903f8b58", - "name" : "Max Clients Limit", - "providerId" : "max-clients", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "max-clients" : [ "200" ] - } - } ], - "org.keycloak.keys.KeyProvider" : [ { - "id" : "6447c1d0-4b09-4140-848b-ec14db7531b4", - "name" : "hmac-generated-hs512", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "9fbefe4d-c500-4853-aeb8-a6893f7c7203" ], - "secret" : [ "MGArI5-LH4LdC-kGdQ9ZSvqlVB3oLTZlEvZ-pkl2MukIGC_jxxh14P4GElp62GZD2GkH-hJf9H2Xc1DHEhk-mqXFcmJZbb1NeYH_cgu3AAYgtO3trAVftcdhbhMnzVSrLc4QFII-Um6OrC3YlnRE3wBGPe7NJ44l1URc1jsEZh4" ], - "priority" : [ "100" ], - "algorithm" : [ "HS512" ] - } - }, { - "id" : "d89fd5f0-2406-4ec4-b617-562870a59547", - "name" : "rsa-enc-generated", - "providerId" : "rsa-enc-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEpAIBAAKCAQEAx+KBq+YPmK7IcQ4gtSr2jHdBAcja0uU3bPnMBsIkSO/lqEV6bTb3OsDqpUykYEMPg1STDqJMiQiPzRgiv7v3pQgwbJNQpMiLFtXoNBb3aTLqbtTrHrLu3HXuAZ6+krLSPk1PFOdrokovYDFNMPPWEqVHGJxkwqXq3Zt77p+xJAWjhxJyUUnTlcLdtj9QK0+8eewpy4gKo9AmMympB/BQcBh+kQ/8iNhVmNxlwNtePqvv+YmJKaVHMrl+slfBoUU0ZhfCZQmSy+MFC5GX3OfN9gVzPtDtdNLVbG6dXXxE7KoxlrShBWae4LiSi/17keRJW1yKUe24nqVc3MSpeVU3swIDAQABAoIBACqVXN7MUoJKqjU7t0ghcQkX1ueUbNoFLzuuNAM0lRpc0WZ59s0RqrX/p32zyEkhwEpQWEwD055WDpy5CZ4jY2zrQ7W95K5WcxtYUvHV+ruUt1EJV1Xg9PZOwXfi4+LI6fWP7ssbSlj2yQULO9C0AeVTBMR/fQ/i3Rh9KXf62Xg8wugRRgH11XxSscJRJq+fk9Ig5rx0IsbAJqollQJQxhOhXPUe4Dk1U8jmyuG/ZCPFSqMU+670S3nbsWvog0lAaHik1nPFfqxXntXgQTW8wJxnqjxCHHZGUKjgCEqTqynEQs83dLhnCABSc0S9hU5/GE1+EdL6qlcv6/VreP+7z4ECgYEA5Jk1rGwfxzeGP3fW/VDAK3uMQLvhHUvd63xiu+slSAu5epjmOrgvEDHFN8A2CgfgyPr25Szg+16Mn2U/0ul/YzEEz8z+BXdons/z/uPxvFKFRlWf1qB3UiwigFXJQti4QHqe1YHvvqx4iFUgjtVsfcOkpr57ofnrIMVT9VXeT2ECgYEA39gvwg8Lnx9XwM5TCT2tdqHzWTZ4eqg9FeQPqQQw3GEnhYTfZoC6DFamwCBcd0ALif/KOD/NPGyYVNbB6sxjLWpencyrPveVzsEdVtra46syT60nsC4v5M+O3q2i10sSdVrTBK+oTQTKJnc+I3xStM8ocdcO1SbeMBy7Nh1vg5MCgYBIwgbWUTewFZkR/FeeGqR/cnxKYkIdK/d/KwDV5Nrh2nF3dtDYYaUBF4Y432GTwbwm29HXUXhuKULCvNwaihz0ejaY2RsErGPNIEz9lJltIiqvHzOXgU1ZBxkYFbXQI+BJDX4eYJPo8UYPxmBtdbppMOrn83qwLDZNIOE/FcyDIQKBgQCpmGwmxatydhbQmAJFwBtLBM0RTLnfhNQzX8WVsv0qG9oLyW5RhTpw2r4gVuR33WhguBKIp55iJ40KymPF9/E0maDyQf2FCaTRL3OBOPQbBrxprbGiRHw5CiEfCcOVBuYHUDcNF+GV6QkYN8Q2sp0fLM1h4yTzzi0Nmtck2wyATQKBgQC3+Tkk2ej+S4FAKh0msrg5phseO8CkRcQFhdxyhc0nz2ENJs3xd9RnTkNEGSZxoUk4AlgdCbIZoi447gbj5Q9rahUe3PgRzKsbqpxMyrW13f4R4uKWgr+gcYh0bb/9zFGz7Yw/yd9VxjO6wOsGXYVaW5oLXtfSjCJJsp/54lnpIw==" ], - "keyUse" : [ "ENC" ], - "certificate" : [ "MIICozCCAYsCBgGSXmLbbDANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApoZXBoYWVzdHVzMB4XDTI0MTAwNTIwMzEyOVoXDTM0MTAwNTIwMzMwOVowFTETMBEGA1UEAwwKaGVwaGFlc3R1czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMfigavmD5iuyHEOILUq9ox3QQHI2tLlN2z5zAbCJEjv5ahFem029zrA6qVMpGBDD4NUkw6iTIkIj80YIr+796UIMGyTUKTIixbV6DQW92ky6m7U6x6y7tx17gGevpKy0j5NTxTna6JKL2AxTTDz1hKlRxicZMKl6t2be+6fsSQFo4cSclFJ05XC3bY/UCtPvHnsKcuICqPQJjMpqQfwUHAYfpEP/IjYVZjcZcDbXj6r7/mJiSmlRzK5frJXwaFFNGYXwmUJksvjBQuRl9znzfYFcz7Q7XTS1WxunV18ROyqMZa0oQVmnuC4kov9e5HkSVtcilHtuJ6lXNzEqXlVN7MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAEEKp/6JbjbYTRBKIOT44Wa3O9VGJ65B2B1rakXPSInXhgbKHeLxZyY69O56yOrIzLcb/Q1ufD1F9+THzVuRPnh505BTjsM2JUF8E7m7Paz2uPng3K+NnRp8TQOZfrkSS39cgtsZ/3BP1u+5Ra/vm0/ShYOJ8kl94YzSJ0MY1oVNyUtsG+v33IZZsLcN4HPR80wdCedqn5Yt4mGie0uBMD8lYBfr/ie0D113A5XSKq0GXw6vOWL5/88+ZUK64f8g/ujFX/kUc9emhA852v2QI5azrEQZfALLe7r9I4dLhu/ULMNMYV7JZukmgjevbTD3oGHI2OY5RSy9eNnqo4Don8Q==" ], - "priority" : [ "100" ], - "algorithm" : [ "RSA-OAEP" ] - } - }, { - "id" : "d9ce5a63-3167-4216-a290-ffa39975a506", - "name" : "rsa-generated", - "providerId" : "rsa-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEowIBAAKCAQEAzQkKjEUeGuE+s0GHi6W4ljjn3H+07Ts9I3xuQbU8wTK2qrZOnlV7FxOD40xhNnTUXl5XsdkZ51/40hxcFZNCNWEJ6s31WF86Y7NrigNkIZDIgW1B0Dsz4w9DbSeg8eJh2h0494+39vIra7lYi7DtcRD+Bi4HwaOtbP2NpxPYOm2FgRCvnjnH1PtkDg3hcQPVDSWPFegbbIolmC2yupi3zulbGi4+dzl75V5cDTpJ7y84Aqo14KIUMqs2hTSmCKncTiU+kcxc/wZCLLFycLTLwGRkz2Zw0U68ZxGhCDazD3tj9eN1p35km2Fd46qSvqR3rhEi+Q4J3E27oKoPW2kPMQIDAQABAoIBABt59zJl/stOXRcrlG0H580l0hiP+qCB/Eb5oVLn5TzkvWryJGX+gZDNmjKHJU3laSI+VVUtiVWi3FbX2xU/FzPNDcWsFRFjLZF31VT48F25J82EZTnw/RqUDI6frWdM1Z0jpmMynM4YlO4KOA38R02MH+aXG439D7wX3HhD5gmqLubZJ0V+xJowCR9punK3B0IhEUW0sQJxUn4qjzDS6CQRUdUY1vFyHVu//yCYniIVIR9W0SuOv9oM5Hk+k16wg5pWK/BP7ZsMoYmVJBJl2wgyV/X3H/2s5XO6JPV522pO/SNFye6PP41P6N7SQgSvCjJDYbCNm2uNK41vxVfsuxkCgYEA/qZWsHOvP1oS+Ezzqr7TKTmFQtX091EHJB3IZoD5lutA5W4we4sDUtbBKyejKRQJ1j+ncFSumucDVZkBARP1Zbxdbfq6hRp+IteKUE/9id1h8ZI0OoV038IHY3j77SKOWuS9PzeLowDcuvkjGeSzEk2jzl3mS+wc+2lI3LDxwx0CgYEAzh9bINQsAB96ehUdIfGW8Ni7d6x1H8oeUBfMUGWTRBKeN3wyWEXx11PchUBAMyBlZsL/ff1mnVCW4lUXr+/xRhWr0uhtl4Dk22UbTxa8Bncao53/Px6hPIp3zkBBja2LY2RItFI2Dsm9i1P0+XjyyLjGaSwpiQ68XvU++8mUjCUCgYBrLhfOrOJWB9N0Lu9gLnEyKMOuHd+9OJ2I1gBDJIXov5vQ9U/yr8/2Te1//G7wGz8IrkILRZk4GYONw5hom73t1Bp+78kRvNTaVV4h74kHPea7ho31E7bddw0lEQb4CFNibmQ492gOc450I+hiPaAhVAxeD6eezQJlzyqbuN4JAQKBgQC0Z51Kzmj0cpiv4WruGpURl5/8zmR0vmJpl2qrszuBiQoRZhJqUE2rOSr5NZL7LI+TsXgMvYzig3aMAg4JXui9fpo0rlm9EIM9wvBz+GH5BqW6Lr8Ib7aPVmIlkvfNGOe2xj8cFBhcORY8q+7tqn5UT+TYiF6SJuOX+O53UadCQQKBgBfLIjuO2fdCkXbfteh++GBsuPfjq8ueQVkgxLWSIIW7DH0TWszwXaF1U9SsnI7QLT+E6jyUnhBkQDbabcNSQiXXLG1VWdO/vPMZsjxMkr8TptnA+QoWH0suwyGMhAmW2/KDO6rr5yRHRBpxYGyZYjZyWjX/ZN40QBf0HEIHtZYF" ], - "keyUse" : [ "SIG" ], - "certificate" : [ "MIICozCCAYsCBgGSXmLbFzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApoZXBoYWVzdHVzMB4XDTI0MTAwNTIwMzEyOVoXDTM0MTAwNTIwMzMwOVowFTETMBEGA1UEAwwKaGVwaGFlc3R1czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM0JCoxFHhrhPrNBh4uluJY459x/tO07PSN8bkG1PMEytqq2Tp5VexcTg+NMYTZ01F5eV7HZGedf+NIcXBWTQjVhCerN9VhfOmOza4oDZCGQyIFtQdA7M+MPQ20noPHiYdodOPePt/byK2u5WIuw7XEQ/gYuB8GjrWz9jacT2DpthYEQr545x9T7ZA4N4XED1Q0ljxXoG2yKJZgtsrqYt87pWxouPnc5e+VeXA06Se8vOAKqNeCiFDKrNoU0pgip3E4lPpHMXP8GQiyxcnC0y8BkZM9mcNFOvGcRoQg2sw97Y/Xjdad+ZJthXeOqkr6kd64RIvkOCdxNu6CqD1tpDzECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAomBGjy7IDy5+86O/rFzgumCWQQMsx/MMGFV+jk2wEphkV2qNDxzT2waDbrKVqCZhV//G61f6aVeSZkTPGZDWrA19Ac/9LqBPRnW9QaefbDiYnW2i6abvpSpSzDiYBi6msDTzId0oP05zUdMg7Eud0OgaTJ+Q9/VFLmBHmQaTXaV/7PAl3XFFoy+ckeS9ZFHZRwKqzQ2F5aoyu55EBiCgreDYkFvpaIbN3A+ElNpwui7QY0RG1rClEya9p9ibZ2WEX4zjp9D+IMKctjpw1csYUwJ8SpqMtO9TQM98zJES2aPl7oo5DnVnUtGxhJSr64Gp8uo/qYzWHWaM6h4IX6jGWg==" ], - "priority" : [ "100" ] - } - }, { - "id" : "cc996409-8e41-4671-b18b-8d4255fd30d0", - "name" : "aes-generated", - "providerId" : "aes-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "6cc95ace-9442-4db5-a891-49e3aafe74b4" ], - "secret" : [ "nRELQmJK5tzxp0Wqydpcng" ], - "priority" : [ "100" ] - } - } ] - }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], - "authenticationFlows" : [ { - "id" : "f85d840f-75c3-4df4-ae43-0501b35e3000", - "alias" : "Account verification options", - "description" : "Method with which to verity the existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-email-verification", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false - } ] - }, { - "id" : "fdd5bf34-07a2-4f7f-a27b-607316c1cdc9", - "alias" : "Browser - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "5fe895b4-993d-4a89-9d08-f4e9898c67f6", - "alias" : "Browser - Conditional Organization", - "description" : "Flow to determine if the organization identity-first login is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "organization", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "500616bb-c431-4096-a49e-0df1ef41cff5", - "alias" : "Direct Grant - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "4607238a-087e-4403-905d-3833ab84002b", - "alias" : "First Broker Login - Conditional Organization", - "description" : "Flow to determine if the authenticator that adds organization members is to be used", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "idp-add-organization-member", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "643831d9-db9a-464d-a9b1-ccc3effac995", - "alias" : "First broker login - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "ee88c7af-8c55-42ab-9469-5715fa035705", - "alias" : "Handle Existing Account", - "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-confirm-link", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Account verification options", - "userSetupAllowed" : false - } ] - }, { - "id" : "47788773-ba07-46ad-9d5b-5d28434db7d0", - "alias" : "Organization", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "9b885aa9-5f5d-4e9f-b433-4c5ccbee1011", - "alias" : "Reset - Conditional OTP", - "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "8abdbd0c-81db-42a2-a7e4-dc48b5a93230", - "alias" : "User creation or linking", - "description" : "Flow for the existing/non-existing user alternatives", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "create unique user config", - "authenticator" : "idp-create-user-if-unique", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false - } ] - }, { - "id" : "f21b5b62-8026-409e-b520-a81589b6b506", - "alias" : "Verify Existing Account by Re-authentication", - "description" : "Reauthentication of existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "cf9f8864-670f-4067-9242-146f6660c603", - "alias" : "browser", - "description" : "Browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 26, - "autheticatorFlow" : true, - "flowAlias" : "Organization", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "forms", - "userSetupAllowed" : false - } ] - }, { - "id" : "ad9e7782-cd6b-4250-87ca-be3b841e7c3f", - "alias" : "clients", - "description" : "Base authentication for clients", - "providerId" : "client-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "client-secret", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-secret-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-x509", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 40, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "7781a9a1-f376-4755-b91c-aab751a0f884", - "alias" : "direct grant", - "description" : "OpenID Connect Resource Owner Grant", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "direct-grant-validate-username", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "c554d494-b117-4a66-97b7-1ac09fb14442", - "alias" : "docker auth", - "description" : "Used by Docker clients to authenticate against the IDP", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "docker-http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "dd085248-fef6-41cb-8a5a-4826a4f3522e", - "alias" : "first broker login", - "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "review profile config", - "authenticator" : "idp-review-profile", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "User creation or linking", - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 50, - "autheticatorFlow" : true, - "flowAlias" : "First Broker Login - Conditional Organization", - "userSetupAllowed" : false - } ] - }, { - "id" : "215253c4-d9f1-4ca6-8bbf-70da1323832f", - "alias" : "forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "7319086a-99d5-474a-ab8f-9d908ad8dd18", - "alias" : "registration", - "description" : "Registration flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-page-form", - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "registration form", - "userSetupAllowed" : false - } ] - }, { - "id" : "0e642b52-d4b8-483c-835f-5d4b9ff89dda", - "alias" : "registration form", - "description" : "Registration form", - "providerId" : "form-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-user-creation", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-password-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 50, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-recaptcha-action", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 60, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-terms-and-conditions", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 70, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "62dcd4c7-c2d7-4b18-9ff2-d383eb1239ab", - "alias" : "reset credentials", - "description" : "Reset credentials for a user if they forgot their password or something", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "reset-credentials-choose-user", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-credential-email", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 40, - "autheticatorFlow" : true, - "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "49b8c4ba-4385-4773-ab75-3229ab9d309e", - "alias" : "saml ecp", - "description" : "SAML ECP Profile Authentication Flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - } ], - "authenticatorConfig" : [ { - "id" : "bd1ac3c1-5c3a-493a-abc1-0f31269f372c", - "alias" : "create unique user config", - "config" : { - "require.password.update.after.registration" : "false" - } - }, { - "id" : "3d23706b-e877-4f86-88ab-1587a3642dbd", - "alias" : "review profile config", - "config" : { - "update.profile.on.first.login" : "missing" + "clientPolicies": { + "policies": [] } - } ], - "requiredActions" : [ { - "alias" : "CONFIGURE_TOTP", - "name" : "Configure OTP", - "providerId" : "CONFIGURE_TOTP", - "enabled" : true, - "defaultAction" : false, - "priority" : 10, - "config" : { } - }, { - "alias" : "TERMS_AND_CONDITIONS", - "name" : "Terms and Conditions", - "providerId" : "TERMS_AND_CONDITIONS", - "enabled" : false, - "defaultAction" : false, - "priority" : 20, - "config" : { } - }, { - "alias" : "UPDATE_PASSWORD", - "name" : "Update Password", - "providerId" : "UPDATE_PASSWORD", - "enabled" : true, - "defaultAction" : false, - "priority" : 30, - "config" : { } - }, { - "alias" : "UPDATE_PROFILE", - "name" : "Update Profile", - "providerId" : "UPDATE_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 40, - "config" : { } - }, { - "alias" : "VERIFY_EMAIL", - "name" : "Verify Email", - "providerId" : "VERIFY_EMAIL", - "enabled" : true, - "defaultAction" : false, - "priority" : 50, - "config" : { } - }, { - "alias" : "delete_account", - "name" : "Delete Account", - "providerId" : "delete_account", - "enabled" : false, - "defaultAction" : false, - "priority" : 60, - "config" : { } - }, { - "alias" : "webauthn-register", - "name" : "Webauthn Register", - "providerId" : "webauthn-register", - "enabled" : true, - "defaultAction" : false, - "priority" : 70, - "config" : { } - }, { - "alias" : "webauthn-register-passwordless", - "name" : "Webauthn Register Passwordless", - "providerId" : "webauthn-register-passwordless", - "enabled" : true, - "defaultAction" : false, - "priority" : 80, - "config" : { } - }, { - "alias" : "VERIFY_PROFILE", - "name" : "Verify Profile", - "providerId" : "VERIFY_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 90, - "config" : { } - }, { - "alias" : "delete_credential", - "name" : "Delete Credential", - "providerId" : "delete_credential", - "enabled" : true, - "defaultAction" : false, - "priority" : 100, - "config" : { } - }, { - "alias" : "update_user_locale", - "name" : "Update User Locale", - "providerId" : "update_user_locale", - "enabled" : true, - "defaultAction" : false, - "priority" : 1000, - "config" : { } - } ], - "browserFlow" : "browser", - "registrationFlow" : "registration", - "directGrantFlow" : "direct grant", - "resetCredentialsFlow" : "reset credentials", - "clientAuthenticationFlow" : "clients", - "dockerAuthenticationFlow" : "docker auth", - "firstBrokerLoginFlow" : "first broker login", - "attributes" : { - "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaAuthRequestedUserHint" : "login_hint", - "oauth2DevicePollingInterval" : "5", - "clientOfflineSessionMaxLifespan" : "0", - "clientSessionIdleTimeout" : "0", - "clientOfflineSessionIdleTimeout" : "0", - "cibaInterval" : "5", - "realmReusableOtpCode" : "false", - "cibaExpiresIn" : "120", - "oauth2DeviceCodeLifespan" : "600", - "parRequestUriLifespan" : "60", - "clientSessionMaxLifespan" : "0", - "frontendUrl" : "", - "organizationsEnabled" : "false", - "acr.loa.map" : "{}" - }, - "keycloakVersion" : "26.0.0", - "userManagedAccessAllowed" : false, - "organizationsEnabled" : false, - "clientProfiles" : { - "profiles" : [ ] - }, - "clientPolicies" : { - "policies" : [ ] - } -} \ No newline at end of file +} diff --git a/server/application-server/openapi.yaml b/server/application-server/openapi.yaml index c9fb4d0e..d01f4540 100644 --- a/server/application-server/openapi.yaml +++ b/server/application-server/openapi.yaml @@ -99,6 +99,14 @@ paths: application/json: schema: $ref: "#/components/schemas/AuthUserInfo" + /user: + delete: + tags: + - user + operationId: deleteUser + responses: + "200": + description: OK components: schemas: PullRequestInfo: diff --git a/server/application-server/pom.xml b/server/application-server/pom.xml index ee059f6d..0ec743a1 100644 --- a/server/application-server/pom.xml +++ b/server/application-server/pom.xml @@ -201,6 +201,11 @@ org.hibernate.validator hibernate-validator + + org.keycloak + keycloak-admin-client + 26.0.3 + diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/OpenAPIConfiguration.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/OpenAPIConfiguration.java index a225cbe5..3079f977 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/OpenAPIConfiguration.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/OpenAPIConfiguration.java @@ -44,63 +44,99 @@ public OpenApiCustomizer schemaCustomizer() { return openApi -> { var components = openApi.getComponents(); - // Only include schemas with DTO suffix and remove the suffix - var schemas = components - .getSchemas() - .entrySet() - .stream() - .filter(entry -> entry.getKey().endsWith("DTO")) - .collect(Collectors.toMap(entry -> entry.getKey().substring(0, entry.getKey().length() - 3), + if (components != null && components.getSchemas() != null) { + // Only include schemas with DTO suffix and remove the suffix + var schemas = components + .getSchemas() + .entrySet() + .stream() + .filter(entry -> entry.getKey().endsWith("DTO")) + .collect(Collectors.toMap( + entry -> entry.getKey().substring(0, entry.getKey().length() - 3), entry -> { var schema = entry.getValue(); schema.setName(entry.getKey().substring(0, entry.getKey().length() - 3)); return schema; - })); + } + )); - // Remove DTO suffix from attribute names - schemas.forEach((key, value) -> { - Map> properties = value.getProperties(); - if (properties != null) { - properties.forEach((propertyKey, propertyValue) -> { - removeDTOSuffixesFromSchemaRecursively(propertyValue); - }); - } - }); + // Remove DTO suffix from attribute names + schemas.forEach((key, value) -> { + Map> properties = value.getProperties(); + if (properties != null) { + properties.forEach((propertyKey, propertyValue) -> { + removeDTOSuffixesFromSchemaRecursively(propertyValue); + }); + } + }); - components.setSchemas(schemas); + components.setSchemas(schemas); + } else { + logger.warn("Components or Schemas are null in OpenAPI configuration."); + } var paths = openApi.getPaths(); - paths.forEach((path, pathItem) -> { - logger.info(path); - pathItem.readOperations().forEach(operation -> { - // Remove DTO suffix from reponse schemas - var responses = operation.getResponses(); - responses.forEach((responseCode, response) -> { - var content = response.getContent(); - content.forEach((contentType, mediaType) -> { - removeDTOSuffixesFromSchemaRecursively(mediaType.getSchema()); + if (paths != null) { + paths.forEach((path, pathItem) -> { + logger.info("Processing path: {}", path); + pathItem.readOperations().forEach(operation -> { + // Remove DTO suffix from response schemas + var responses = operation.getResponses(); + if (responses != null) { + responses.forEach((responseCode, response) -> { + var content = response.getContent(); + if (content != null) { + content.forEach((contentType, mediaType) -> { + if (mediaType != null && mediaType.getSchema() != null) { + removeDTOSuffixesFromSchemaRecursively(mediaType.getSchema()); + } else { + logger.warn("MediaType or Schema is null for content type: {}", contentType); + } + }); + } else { + logger.warn("Response with code {} has no content.", responseCode); + } + }); + } - }); + // Remove -controller suffix from tags + if (operation.getTags() != null) { + operation.setTags( + operation.getTags() + .stream() + .filter(tag -> { + if (tag.length() > 11) { + return true; + } else { + logger.warn("Tag '{}' is shorter than expected and cannot be trimmed.", tag); + return false; + } + }) + .map(tag -> tag.substring(0, tag.length() - 11)) + .collect(Collectors.toList()) + ); + } }); - - // Remove -controller suffix from tags - operation.setTags(operation.getTags() - .stream() - .map(tag -> tag.substring(0, tag.length() - 11)).toList()); }); - }); - - + } else { + logger.warn("Paths are null in OpenAPI configuration."); + } }; } private void removeDTOSuffixesFromSchemaRecursively(Schema schema) { + if (schema == null) { + return; + } + if (schema.get$ref() != null && schema.get$ref().endsWith("DTO")) { - schema.set$ref(schema.get$ref().substring(0, schema.get$ref().length() - 3)); + String newRef = schema.get$ref().substring(0, schema.get$ref().length() - 3); + schema.set$ref(newRef); + logger.debug("Updated $ref from {} to {}", schema.get$ref(), newRef); } if (schema.getItems() != null) { removeDTOSuffixesFromSchemaRecursively(schema.getItems()); } } -} \ No newline at end of file +} diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/KeycloakConfig.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/KeycloakConfig.java new file mode 100644 index 00000000..9eea4f0d --- /dev/null +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/config/KeycloakConfig.java @@ -0,0 +1,35 @@ +package de.tum.in.www1.hephaestus.config; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.KeycloakBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.beans.factory.annotation.Value; + + +@Configuration +public class KeycloakConfig { + + @Value("${keycloak.url}") + private String authServerUrl; + + @Value("${keycloak.realm}") + private String realm; + + @Value("${keycloak.client-id}") + private String clientId; + + @Value("${keycloak.client-secret}") + private String clientSecret; + + @Bean + public Keycloak keycloakClient() { + return KeycloakBuilder.builder() + .serverUrl(authServerUrl) + .realm(realm) + .grantType(OAuth2Constants.CLIENT_CREDENTIALS) + .clientId(clientId) + .clientSecret(clientSecret) + .build(); + } +} diff --git a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/gitprovider/user/UserController.java b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/gitprovider/user/UserController.java index bd9ef741..35f0e773 100644 --- a/server/application-server/src/main/java/de/tum/in/www1/hephaestus/gitprovider/user/UserController.java +++ b/server/application-server/src/main/java/de/tum/in/www1/hephaestus/gitprovider/user/UserController.java @@ -1,8 +1,16 @@ package de.tum.in.www1.hephaestus.gitprovider.user; import java.util.Optional; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.UsersResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; +import org.springframework.security.oauth2.core.oidc.StandardClaimNames; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -11,7 +19,16 @@ @RestController @RequestMapping("/user") public class UserController { - private final UserService userService; + + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + + @Autowired + private UserService userService; + @Autowired + private Keycloak keycloak; + @Value("${keycloak.realm}") + private String realm; + public UserController(UserService actorService) { this.userService = actorService; @@ -22,4 +39,21 @@ public ResponseEntity getUserProfile(@PathVariable String login) Optional userProfile = userService.getUserProfile(login); return userProfile.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } + + @DeleteMapping + public ResponseEntity deleteUser(JwtAuthenticationToken auth) { + if (auth == null) { + logger.error("No authentication token found."); + return ResponseEntity.badRequest().body(null); + } + + String userId = auth.getToken().getClaimAsString(StandardClaimNames.SUB); + logger.info("Deleting user {}", userId); + var response = keycloak.realm(realm).users().delete(userId); + if (response.getStatus() != 204) { + logger.error("Failed to delete user account: {}", response.getStatusInfo().getReasonPhrase()); + return ResponseEntity.badRequest().body(null); + } + return ResponseEntity.ok().build(); + } } diff --git a/server/application-server/src/main/resources/application-prod.yml b/server/application-server/src/main/resources/application-prod.yml index be9eaadc..6c8c4c88 100644 --- a/server/application-server/src/main/resources/application-prod.yml +++ b/server/application-server/src/main/resources/application-prod.yml @@ -23,6 +23,13 @@ hephaestus: enabled: ${LEADERBOARD_NOTIFICATION_ENABLED:true} channel-id: ${LEADERBOARD_NOTIFICATION_CHANNEL_ID:G6TCVL6HL} +keycloak: + url: ${KEYCLOAK_URL} + realm: ${KEYCLOAK_REALM} + client-id: ${KEYCLOAK_CLIENT_ID} + client-secret: ${KEYCLOAK_CLIENT_SECRET} + + nats: enabled: ${NATS_ENABLED:false} timeframe: ${MONITORING_TIMEFRAME:7} diff --git a/server/application-server/src/main/resources/application.yml b/server/application-server/src/main/resources/application.yml index 2dc51f1a..c7ec6ed7 100644 --- a/server/application-server/src/main/resources/application.yml +++ b/server/application-server/src/main/resources/application.yml @@ -41,6 +41,11 @@ hephaestus: enabled: false channel-id: "" +keycloak: + url: http://localhost:8081 + realm: hephaestus + client-id: hephaestus-confidential + client-secret: 0g0QtFmz6GB1Jv03SszCFepPro0hiP7G nats: enabled: false diff --git a/webapp/src/app/app.routes.ts b/webapp/src/app/app.routes.ts index e8cc848a..14889f4a 100644 --- a/webapp/src/app/app.routes.ts +++ b/webapp/src/app/app.routes.ts @@ -4,6 +4,7 @@ import { HomeComponent } from '@app/home/home.component'; import { AdminComponent } from '@app/admin/admin.component'; import { AdminGuard } from '@app/core/security/admin.guard'; import { UserProfileComponent } from '@app/user/user-profile.component'; +import { SettingsComponent } from '@app/settings/settings.component'; import { ImprintComponent } from '@app/legal/imprint/imprint.component'; export const routes: Routes = [ @@ -15,5 +16,6 @@ export const routes: Routes = [ canActivate: [AdminGuard] }, { path: 'user/:id', component: UserProfileComponent }, + { path: 'settings', component: SettingsComponent }, { path: 'imprint', component: ImprintComponent } ]; diff --git a/webapp/src/app/core/header/header.component.html b/webapp/src/app/core/header/header.component.html index 8be8e399..2db35759 100644 --- a/webapp/src/app/core/header/header.component.html +++ b/webapp/src/app/core/header/header.component.html @@ -25,6 +25,10 @@ My Profile + + + Settings + + + +

Are you absolutely sure?

+

This action cannot be undone. This will permanently delete your account and remove your data from our servers.

+
+ + + + +
+ +
+ ` +}) +export class SettingsComponent { + router = inject(Router); + securityStore = inject(SecurityStore); + userService = inject(UserService); + + mutation = injectMutation(() => ({ + mutationFn: () => lastValueFrom(this.userService.deleteUser()), + onSuccess: () => { + this.securityStore.signOut(); + this.router.navigate(['/']); + } + })); + + deleteAccount() { + this.mutation.mutate(); + } +}