mirror of
https://github.com/zitadel/zitadel.git
synced 2025-04-27 20:50:51 +00:00
Merge remote-tracking branch 'origin/main' into user-v3-authenticator
This commit is contained in:
commit
82b87b5571
@ -3,6 +3,34 @@
|
||||
Dear community!
|
||||
We're excited to announce bi-weekly office hours.
|
||||
|
||||
## #5 Q&A
|
||||
|
||||
Dear community,
|
||||
|
||||
This week's office hour is dedicated for you to drop by and ask any questions you may have about ZITADEL. We are happy to discuss anything, from Actions to Zero downtime deployments.
|
||||
|
||||
Join us on the stage or ask your questions in the chat next Wednesday in the office hours channel on Discord. We're looking forward to have a nice chat with you.
|
||||
|
||||
**What to expect:**
|
||||
|
||||
* **Q&A Session**: Ask your questions and feel free to join the discussion to help others getting their questions answered
|
||||
|
||||
**Details:**
|
||||
|
||||
* **Target Audience:** Developers and IT Ops personnel using ZITADEL
|
||||
* **Topic:** Q\&A session
|
||||
* **When**: Wednesday 25th of September 6 pm UTC
|
||||
* **Duration**: about 1 hour
|
||||
* **Platform:** Zitadel Discord Server (Join us here: https://discord.gg/zitadel-927474939156643850?event=1286221582838272000 )
|
||||
|
||||
**In the meantime:**
|
||||
|
||||
If you have questions upfront, feel free to already post them in the chat of the [office hours channel](https://zitadel.com/office-hours) on our Discord server :gigi:
|
||||
|
||||
We look forward to seeing you there\!
|
||||
|
||||
**P.S.** Spread the word\! Share this announcement with your fellow ZITADEL users who might be interested 📢
|
||||
|
||||
## #4 Login UI deepdive
|
||||
|
||||
Dear community,
|
||||
|
@ -28,7 +28,7 @@
|
||||
"@fortawesome/angular-fontawesome": "^0.13.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.2",
|
||||
"@grpc/grpc-js": "^1.11.1",
|
||||
"@grpc/grpc-js": "^1.11.2",
|
||||
"@netlify/framework-info": "^9.8.13",
|
||||
"@ngx-translate/core": "^15.0.0",
|
||||
"angular-oauth2-oidc": "^15.0.1",
|
||||
@ -42,14 +42,14 @@
|
||||
"google-protobuf": "^3.21.2",
|
||||
"grpc-web": "^1.4.1",
|
||||
"i18n-iso-countries": "^7.7.0",
|
||||
"libphonenumber-js": "^1.11.4",
|
||||
"libphonenumber-js": "^1.11.8",
|
||||
"material-design-icons-iconfont": "^6.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"ngx-color": "^9.0.0",
|
||||
"opentype.js": "^1.3.4",
|
||||
"rxjs": "~7.8.0",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"tslib": "^2.6.2",
|
||||
"tslib": "^2.7.0",
|
||||
"uuid": "^10.0.0",
|
||||
"zone.js": "~0.13.3"
|
||||
},
|
||||
@ -60,16 +60,16 @@
|
||||
"@angular-eslint/eslint-plugin-template": "18.0.0",
|
||||
"@angular-eslint/schematics": "16.2.0",
|
||||
"@angular-eslint/template-parser": "18.3.0",
|
||||
"@angular/cli": "^16.2.14",
|
||||
"@angular/cli": "^16.2.15",
|
||||
"@angular/compiler-cli": "^16.2.5",
|
||||
"@angular/language-service": "^18.2.2",
|
||||
"@bufbuild/buf": "^1.39.0",
|
||||
"@angular/language-service": "^18.2.4",
|
||||
"@bufbuild/buf": "^1.41.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/google-protobuf": "^3.15.3",
|
||||
"@types/jasmine": "~5.1.4",
|
||||
"@types/jasminewd2": "~2.0.13",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
"@types/node": "^22.5.2",
|
||||
"@types/node": "^22.5.5",
|
||||
"@types/opentype.js": "^1.3.8",
|
||||
"@types/qrcode": "^1.5.2",
|
||||
"@types/uuid": "^10.0.0",
|
||||
@ -77,7 +77,7 @@
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"codelyzer": "^6.0.2",
|
||||
"eslint": "^8.50.0",
|
||||
"jasmine-core": "~5.2.0",
|
||||
"jasmine-core": "~5.3.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "^6.4.2",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
|
@ -154,10 +154,25 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="state">
|
||||
<th mat-header-cell *matHeaderCellDef>{{ 'PROJECT.GRANT.STATE' | translate }}</th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
<span
|
||||
class="state"
|
||||
[ngClass]="{
|
||||
active: grant.state === UserGrantState.USER_GRANT_STATE_ACTIVE,
|
||||
inactive: grant.state === UserGrantState.USER_GRANT_STATE_INACTIVE,
|
||||
}"
|
||||
>
|
||||
{{ 'USER.DATA.STATE' + grant.state | translate }}
|
||||
</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions" stickyEnd>
|
||||
<th mat-header-cell *matHeaderCellDef class="user-tr-actions"></th>
|
||||
<td mat-cell class="user-tr-actions" *matCellDef="let grant; let i = index">
|
||||
<cnsl-table-actions [hasActions]="true">
|
||||
<cnsl-table-actions [hasActions]="!context.includes('user')">
|
||||
<button
|
||||
actions
|
||||
matTooltip="{{ 'ACTIONS.REMOVE' | translate }}"
|
||||
|
@ -8,7 +8,13 @@ import { tap } from 'rxjs/operators';
|
||||
import { enterAnimations } from 'src/app/animations';
|
||||
import { UserGrant as AuthUserGrant } from 'src/app/proto/generated/zitadel/auth_pb';
|
||||
import { Role } from 'src/app/proto/generated/zitadel/project_pb';
|
||||
import { Type, UserGrant as MgmtUserGrant, UserGrantQuery, UserGrant } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import {
|
||||
Type,
|
||||
UserGrant as MgmtUserGrant,
|
||||
UserGrant,
|
||||
UserGrantQuery,
|
||||
UserGrantState,
|
||||
} from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
@ -66,6 +72,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
public UserGrantContext: any = UserGrantContext;
|
||||
public Type: any = Type;
|
||||
public ActionKeysType: any = ActionKeysType;
|
||||
public UserGrantState: any = UserGrantState;
|
||||
@Input() public type: Type | undefined = undefined;
|
||||
|
||||
public filterOpen: boolean = false;
|
||||
@ -86,6 +93,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
'type',
|
||||
'creationDate',
|
||||
'changeDate',
|
||||
'state',
|
||||
'roleNamesList',
|
||||
'actions',
|
||||
];
|
||||
|
@ -17,6 +17,7 @@
|
||||
'type',
|
||||
'creationDate',
|
||||
'changeDate',
|
||||
'state',
|
||||
'roleNamesList',
|
||||
'actions',
|
||||
]"
|
||||
|
@ -42,7 +42,16 @@
|
||||
[context]="UserGrantContext.GRANTED_PROJECT"
|
||||
[projectId]="projectId"
|
||||
[grantId]="grantId"
|
||||
[displayedColumns]="['select', 'user', 'projectId', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
|
||||
[displayedColumns]="[
|
||||
'select',
|
||||
'user',
|
||||
'projectId',
|
||||
'creationDate',
|
||||
'changeDate',
|
||||
'state',
|
||||
'roleNamesList',
|
||||
'actions',
|
||||
]"
|
||||
[disableWrite]="(['user.grant.write$', 'user.grant.write:' + grantId] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$', 'user.grant.delete:' + grantId] | hasRole | async) === false"
|
||||
[refreshOnPreviousRoutes]="['/grant-create/project/{{projectId}}/grant/{{grantId}}']"
|
||||
|
@ -187,7 +187,7 @@
|
||||
<cnsl-user-grants
|
||||
[context]="UserGrantContext.OWNED_PROJECT"
|
||||
[projectId]="projectId"
|
||||
[displayedColumns]="['select', 'user', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
|
||||
[displayedColumns]="['select', 'user', 'creationDate', 'changeDate', 'state', 'roleNamesList', 'actions']"
|
||||
[refreshOnPreviousRoutes]="['/grant-create/project/' + projectId]"
|
||||
[disableWrite]="(['user.grant.write$', 'user.grant.write:' + projectId] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$', 'user.grant.delete:' + projectId] | hasRole | async) === false"
|
||||
|
@ -136,7 +136,16 @@
|
||||
<cnsl-user-grants
|
||||
[userId]="user.id"
|
||||
[context]="USERGRANTCONTEXT"
|
||||
[displayedColumns]="['org', 'projectId', 'type', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
|
||||
[displayedColumns]="[
|
||||
'org',
|
||||
'projectId',
|
||||
'type',
|
||||
'creationDate',
|
||||
'changeDate',
|
||||
'state',
|
||||
'roleNamesList',
|
||||
'actions',
|
||||
]"
|
||||
[disableWrite]="(['user.grant.write$'] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$'] | hasRole | async) === false"
|
||||
>
|
||||
|
@ -222,7 +222,7 @@
|
||||
<cnsl-user-grants
|
||||
[userId]="user.id"
|
||||
[context]="USERGRANTCONTEXT"
|
||||
[displayedColumns]="['select', 'projectId', 'creationDate', 'changeDate', 'roleNamesList', 'actions']"
|
||||
[displayedColumns]="['select', 'projectId', 'creationDate', 'changeDate', 'state', 'roleNamesList', 'actions']"
|
||||
[disableWrite]="(['user.grant.write$'] | hasRole | async) === false"
|
||||
[disableDelete]="(['user.grant.delete$'] | hasRole | async) === false"
|
||||
>
|
||||
|
@ -26,6 +26,14 @@
|
||||
"@angular-devkit/core" "16.2.14"
|
||||
rxjs "7.8.1"
|
||||
|
||||
"@angular-devkit/architect@0.1602.15":
|
||||
version "0.1602.15"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.1602.15.tgz#b70f2456677f6859d4dac4ad80c6b13d00108797"
|
||||
integrity sha512-+yPlUG5c8l7Z/A6dyeV7NQjj4WDWnWWQt+8eW/KInwVwoYiM32ntTJ0M4uU/aDdHuwKQnMLly28AcSWPWKYf2Q==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "16.2.15"
|
||||
rxjs "7.8.1"
|
||||
|
||||
"@angular-devkit/build-angular@^16.2.2":
|
||||
version "16.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-16.2.14.tgz#0c4e41aa3f67e52b474b2fabeb027aebf6e76566"
|
||||
@ -118,12 +126,24 @@
|
||||
rxjs "7.8.1"
|
||||
source-map "0.7.4"
|
||||
|
||||
"@angular-devkit/schematics@16.2.14":
|
||||
version "16.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.2.14.tgz#819c2ef8bb298e383cb312d9d1411f5970f0328f"
|
||||
integrity sha512-B6LQKInCT8w5zx5Pbroext5eFFRTCJdTwHN8GhcVS8IeKCnkeqVTQLjB4lBUg7LEm8Y7UHXwzrVxmk+f+MBXhw==
|
||||
"@angular-devkit/core@16.2.15":
|
||||
version "16.2.15"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-16.2.15.tgz#44ef98cda82ef82435a2a41507f8c24720d372df"
|
||||
integrity sha512-68BgPWpcjNKz++uvLFG8IZaOH3ti2BWQVqaE3yTIYaMoNt0y0A0X2MUVd7EGbAGUk2JdloWJv5LTPVZMzCuK4w==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "16.2.14"
|
||||
ajv "8.12.0"
|
||||
ajv-formats "2.1.1"
|
||||
jsonc-parser "3.2.0"
|
||||
picomatch "2.3.1"
|
||||
rxjs "7.8.1"
|
||||
source-map "0.7.4"
|
||||
|
||||
"@angular-devkit/schematics@16.2.15":
|
||||
version "16.2.15"
|
||||
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.2.15.tgz#cedcb48fdd240db0a779674cf52455a78a4098bb"
|
||||
integrity sha512-C/j2EwapdBMf1HWDuH89bA9B2e511iEYImkyZ+vCSXRwGiWUaZCrhl18bvztpErTrdOLM3mCwNXWEAMXI4zUXA==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "16.2.15"
|
||||
jsonc-parser "3.2.0"
|
||||
magic-string "0.30.1"
|
||||
ora "5.4.1"
|
||||
@ -242,15 +262,15 @@
|
||||
optionalDependencies:
|
||||
parse5 "^7.1.2"
|
||||
|
||||
"@angular/cli@^16.2.14":
|
||||
version "16.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-16.2.14.tgz#ab58910ae354ee31b89a7479efd5978fd1a3042e"
|
||||
integrity sha512-0y71jtitigVolm4Rim1b8xPQ+B22cGp4Spef2Wunpqj67UowN6tsZaVuWBEQh4u5xauX8LAHKqsvy37ZPWCc4A==
|
||||
"@angular/cli@^16.2.15":
|
||||
version "16.2.15"
|
||||
resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-16.2.15.tgz#951d84ef9a7113242b10fe89be1adfa3a94dd6aa"
|
||||
integrity sha512-nNUmt0ZRj2xHH8tGXSJUiusP5rmakAz0f6cc6T4p03OyeShOKdvs9+/F4hzzsM79/ylZofBlFfwYVCBTbOtMqw==
|
||||
dependencies:
|
||||
"@angular-devkit/architect" "0.1602.14"
|
||||
"@angular-devkit/core" "16.2.14"
|
||||
"@angular-devkit/schematics" "16.2.14"
|
||||
"@schematics/angular" "16.2.14"
|
||||
"@angular-devkit/architect" "0.1602.15"
|
||||
"@angular-devkit/core" "16.2.15"
|
||||
"@angular-devkit/schematics" "16.2.15"
|
||||
"@schematics/angular" "16.2.15"
|
||||
"@yarnpkg/lockfile" "1.1.0"
|
||||
ansi-colors "4.1.3"
|
||||
ini "4.1.1"
|
||||
@ -318,10 +338,10 @@
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@angular/language-service@^18.2.2":
|
||||
version "18.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.2.tgz#8a6b3f224871cb4b1dd5d76a43a1c3884d14aa62"
|
||||
integrity sha512-aROQNQeLf+o+F5OVvE/9BUe/Tpv8pjzmrZlogBbic5cb4IqSNhR4RjxbgIyXBO/6bhLCZwqfmMqRbW2J2xqMkg==
|
||||
"@angular/language-service@^18.2.4":
|
||||
version "18.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@angular/language-service/-/language-service-18.2.4.tgz#c449a75bc405bf519fc90f7a9269a98e2a1f7758"
|
||||
integrity sha512-Keg6n8u8xHLhRDTmx4hUqh1AtVFUt8hDxPMYSUu64czjOT5Dnh8XsgKagu563NEjxbDaCzttPuO+y3DlcaDZoQ==
|
||||
|
||||
"@angular/material-moment-adapter@^16.2.4":
|
||||
version "16.2.14"
|
||||
@ -1462,47 +1482,47 @@
|
||||
"@babel/helper-validator-identifier" "^7.24.7"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bufbuild/buf-darwin-arm64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.39.0.tgz#0ab8453dc7fc7694e5bd39c69d934edc51b81c81"
|
||||
integrity sha512-Ptl0uAGssLxQTzoZhGwv1FFTbzUfcstIpEwMhN+XrwiuqsSxOg9eq/n3yXoci5VJsHokjDUHnWkR3y+j5P/5KA==
|
||||
"@bufbuild/buf-darwin-arm64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.41.0.tgz#a6aee96452f5a624eb7e5b0336833fdd7a3a7911"
|
||||
integrity sha512-+G5DwpIgnm0AkqgxORxoYXVT0RGDcw8P4SXFXcovgvDBkk9rPvEI1dbPF83n3SUxzcu2A2OxC7DxlXszWIh2Gw==
|
||||
|
||||
"@bufbuild/buf-darwin-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.39.0.tgz#9c9a211c8039b8cb89b45bf44f338edf82d5e506"
|
||||
integrity sha512-XNCuy9sjQwVJ4NIZqxaTIyzUtlyquSkp/Uuoh5W5thJ3nzZ5RSgvXKF5iXHhZmesrfRGApktwoCx5Am8runsfQ==
|
||||
"@bufbuild/buf-darwin-x64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.41.0.tgz#aac6a6b86f6d1f30c86f70e918d212e067e5257f"
|
||||
integrity sha512-qjkJ/LAWqNk3HX65n+JTt18WtKrhrrAhIu3Dpfbe0eujsxafFZKoPzlWJYybxvsaF9CdEyMMm/OalBPpoosMOA==
|
||||
|
||||
"@bufbuild/buf-linux-aarch64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.39.0.tgz#9778732efbdbbfe02ec821017cc2392ce4a0153f"
|
||||
integrity sha512-Am+hrw94awp/eY027ROXwRQBuwAzOpQ/4zI4dgmgsyhzeWZ8w1LWC8z2SSr8T2cqd0cm52KxtoWMW+B3b2qzbw==
|
||||
"@bufbuild/buf-linux-aarch64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.41.0.tgz#8ac97e7a19cf0c0957ca1b3e690d8c039b0b3468"
|
||||
integrity sha512-5E+MLAF4QHPwAjwVVRRP3Is2U3zpIpQQR7S3di9HlKACbgvefJEBrUfRqQZvHrMuuynQRqjFuZD16Sfvxn9rCQ==
|
||||
|
||||
"@bufbuild/buf-linux-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.39.0.tgz#d7ca62c4f506c60011f5a97ca2e8683aa26693b0"
|
||||
integrity sha512-JXVkHoMrTvmpseqdoQPJJ6MRV7/vlloYtvXHHACEzVytYjljOYCNoVET/E5gLBco/edeXFMNc40cCi1KgL3rSw==
|
||||
"@bufbuild/buf-linux-x64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.41.0.tgz#8a272846929215affccb9c271f02948e10f8d4a9"
|
||||
integrity sha512-W4T+uqmdtypzzatv6OXjUzGacZiNzGECogr+qDkJF38MSZd3jHXhTEN2KhRckl3i9rRAnfHBwG68BjCTxxBCOQ==
|
||||
|
||||
"@bufbuild/buf-win32-arm64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.39.0.tgz#efdaf1eca30445f04124c6d829a46a676e6b1dc3"
|
||||
integrity sha512-akdGW02mo04wbLfjNMBQqxC4mPQ/L/vTU8/o79I67GSxyFYt7bKifvYIYhAA39C2gibHyB7ZLmoeRPbaU8wbYA==
|
||||
"@bufbuild/buf-win32-arm64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.41.0.tgz#e26b67b2da15e284326c3d3c38255b443e201e0b"
|
||||
integrity sha512-OsRVoTZHJZYGIphAwaRqcCeYR9Sk5VEMjpCJiFt/dkHxx2acKH4u/7O+633gcCxQL8EnsU2l8AfdbW7sQaOvlg==
|
||||
|
||||
"@bufbuild/buf-win32-x64@1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.39.0.tgz#09f2b0290818d826847689d6149f8fb0def4ac4b"
|
||||
integrity sha512-jos08UMg9iUZsGjPrNpLXP+FNk6q6GizO+bjee/GcI0kSijIzXYMg14goQr0TKlvqs/+IRAM5vZIokQBYlAENQ==
|
||||
"@bufbuild/buf-win32-x64@1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.41.0.tgz#b2ff4e9cdb9f73baaad216d35c91c733c4c4b661"
|
||||
integrity sha512-2KJLp7Py0GsfRjDxwBzS17RMpaYFGCvzkwY5CtxfPMw8cg6cE7E36r+vcjHh5dBOj/CumaiXLTwxhCSBtp0V1g==
|
||||
|
||||
"@bufbuild/buf@^1.39.0":
|
||||
version "1.39.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.39.0.tgz#65884f55d072b93122959c92b389c1d7d8ab510b"
|
||||
integrity sha512-lm7xb9pc7X04rRjCQ69o9byAAZ7/dsUQGoH+iJ9uBSXQWiwQ1Ts8gneBnuUVsAH2vdW73NFBpmNQGE9XtFauVQ==
|
||||
"@bufbuild/buf@^1.41.0":
|
||||
version "1.41.0"
|
||||
resolved "https://registry.yarnpkg.com/@bufbuild/buf/-/buf-1.41.0.tgz#76077338696009c2f34e7ca1c76baf89a04079f5"
|
||||
integrity sha512-6pN2fqMrPqnIkrC1q9KpXpu7fv3Rul0ZPhT4MSYYj+8VcyR3kbLVk6K+CzzPvYhr4itfotnI3ZVGQ/X/vupECg==
|
||||
optionalDependencies:
|
||||
"@bufbuild/buf-darwin-arm64" "1.39.0"
|
||||
"@bufbuild/buf-darwin-x64" "1.39.0"
|
||||
"@bufbuild/buf-linux-aarch64" "1.39.0"
|
||||
"@bufbuild/buf-linux-x64" "1.39.0"
|
||||
"@bufbuild/buf-win32-arm64" "1.39.0"
|
||||
"@bufbuild/buf-win32-x64" "1.39.0"
|
||||
"@bufbuild/buf-darwin-arm64" "1.41.0"
|
||||
"@bufbuild/buf-darwin-x64" "1.41.0"
|
||||
"@bufbuild/buf-linux-aarch64" "1.41.0"
|
||||
"@bufbuild/buf-linux-x64" "1.41.0"
|
||||
"@bufbuild/buf-win32-arm64" "1.41.0"
|
||||
"@bufbuild/buf-win32-x64" "1.41.0"
|
||||
|
||||
"@colors/colors@1.5.0":
|
||||
version "1.5.0"
|
||||
@ -1810,10 +1830,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
|
||||
"@grpc/grpc-js@^1.11.1":
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70"
|
||||
integrity sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw==
|
||||
"@grpc/grpc-js@^1.11.2":
|
||||
version "1.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.2.tgz#541a00303e533b5efe9d84ed61b84cdf9dd93ee7"
|
||||
integrity sha512-DWp92gDD7/Qkj7r8kus6/HCINeo3yPZWZ3paKgDgsbKbSpoxKg1yvN8xe2Q8uE3zOsPe3bX8FQX2+XValq2yTw==
|
||||
dependencies:
|
||||
"@grpc/proto-loader" "^0.7.13"
|
||||
"@js-sdsl/ordered-map" "^4.4.2"
|
||||
@ -2884,13 +2904,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
|
||||
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
|
||||
|
||||
"@schematics/angular@16.2.14":
|
||||
version "16.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-16.2.14.tgz#3aac7e05b6e3919195275cf06ac403d7a3567876"
|
||||
integrity sha512-YqIv727l9Qze8/OL6H9mBHc2jVXzAGRNBYnxYWqWhLbfvuVbbldo6NNIIjgv6lrl2LJSdPAAMNOD5m/f6210ug==
|
||||
"@schematics/angular@16.2.15":
|
||||
version "16.2.15"
|
||||
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-16.2.15.tgz#f3b810842959808f0d65ce816f4f0c1a7463c176"
|
||||
integrity sha512-T7wEGYxidpLAkis+hO5nsVfnWsy6sXf1T9GS8uztC8IYYsnqB9jTVfjVyfhASugZasdmx7+jWv3oCGy6Z5ZehA==
|
||||
dependencies:
|
||||
"@angular-devkit/core" "16.2.14"
|
||||
"@angular-devkit/schematics" "16.2.14"
|
||||
"@angular-devkit/core" "16.2.15"
|
||||
"@angular-devkit/schematics" "16.2.15"
|
||||
jsonc-parser "3.2.0"
|
||||
|
||||
"@sigstore/bundle@^1.1.0":
|
||||
@ -3098,10 +3118,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0", "@types/node@^22.5.2":
|
||||
version "22.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793"
|
||||
integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg==
|
||||
"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0", "@types/node@^22.5.5":
|
||||
version "22.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.5.tgz#52f939dd0f65fc552a4ad0b392f3c466cc5d7a44"
|
||||
integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==
|
||||
dependencies:
|
||||
undici-types "~6.19.2"
|
||||
|
||||
@ -3978,10 +3998,10 @@ blocking-proxy@^1.0.0:
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
body-parser@1.20.2, body-parser@^1.19.0:
|
||||
version "1.20.2"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
|
||||
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
|
||||
body-parser@1.20.3, body-parser@^1.19.0:
|
||||
version "1.20.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
|
||||
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
content-type "~1.0.5"
|
||||
@ -3991,7 +4011,7 @@ body-parser@1.20.2, body-parser@^1.19.0:
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
on-finished "2.4.1"
|
||||
qs "6.11.0"
|
||||
qs "6.13.0"
|
||||
raw-body "2.5.2"
|
||||
type-is "~1.6.18"
|
||||
unpipe "1.0.0"
|
||||
@ -4902,6 +4922,11 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
|
||||
|
||||
encodeurl@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
|
||||
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
||||
|
||||
encoding@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
|
||||
@ -5276,36 +5301,36 @@ exponential-backoff@^3.1.1:
|
||||
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
|
||||
|
||||
express@^4.17.3:
|
||||
version "4.19.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
|
||||
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
|
||||
version "4.20.0"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48"
|
||||
integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.20.2"
|
||||
body-parser "1.20.3"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.6.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
encodeurl "~1.0.2"
|
||||
encodeurl "~2.0.0"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
finalhandler "1.2.0"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
merge-descriptors "1.0.1"
|
||||
merge-descriptors "1.0.3"
|
||||
methods "~1.1.2"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.7"
|
||||
path-to-regexp "0.1.10"
|
||||
proxy-addr "~2.0.7"
|
||||
qs "6.11.0"
|
||||
range-parser "~1.2.1"
|
||||
safe-buffer "5.2.1"
|
||||
send "0.18.0"
|
||||
serve-static "1.15.0"
|
||||
send "0.19.0"
|
||||
serve-static "1.16.0"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
type-is "~1.6.18"
|
||||
@ -6482,10 +6507,10 @@ jasmine-core@~2.8.0:
|
||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"
|
||||
integrity sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==
|
||||
|
||||
jasmine-core@~5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-5.2.0.tgz#7d0aa4c26cb3dbaed201d0505489baf1e48faeca"
|
||||
integrity sha512-tSAtdrvWybZkQmmaIoDgnvHG8ORUNw5kEVlO5CvrXj02Jjr9TZrmjFq7FUiOUzJiOP2wLGYT6PgrQgQF4R1xiw==
|
||||
jasmine-core@~5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-5.3.0.tgz#ed784e5a10af43988d8408bad80b9f08e240a3f8"
|
||||
integrity sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==
|
||||
|
||||
jasmine-spec-reporter@~7.0.0:
|
||||
version "7.0.0"
|
||||
@ -6810,10 +6835,10 @@ levn@^0.4.1:
|
||||
prelude-ls "^1.2.1"
|
||||
type-check "~0.4.0"
|
||||
|
||||
libphonenumber-js@^1.11.4:
|
||||
version "1.11.5"
|
||||
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.5.tgz#50a441da5ff9ed9a322d796a14f1e9cbc0fdabdf"
|
||||
integrity sha512-TwHR5BZxGRODtAfz03szucAkjT5OArXr+94SMtAM2pYXIlQNVMrxvb6uSCbnaJJV6QXEyICk7+l6QPgn72WHhg==
|
||||
libphonenumber-js@^1.11.8:
|
||||
version "1.11.8"
|
||||
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.8.tgz#697fdd36500a97bc672d7927d867edf34b4bd2a7"
|
||||
integrity sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg==
|
||||
|
||||
license-webpack-plugin@4.0.2:
|
||||
version "4.0.2"
|
||||
@ -7034,10 +7059,10 @@ memfs@^3.4.12, memfs@^3.4.3:
|
||||
dependencies:
|
||||
fs-monkey "^1.0.4"
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
|
||||
merge-descriptors@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
|
||||
integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
@ -7855,10 +7880,10 @@ path-scurry@^1.11.1:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||
integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
|
||||
path-to-regexp@0.1.10:
|
||||
version "0.1.10"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
|
||||
integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
|
||||
|
||||
path-type@^4.0.0:
|
||||
version "4.0.0"
|
||||
@ -8145,6 +8170,13 @@ qs@6.11.0:
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@6.13.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
|
||||
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
|
||||
dependencies:
|
||||
side-channel "^1.0.6"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||
@ -8618,6 +8650,25 @@ send@0.18.0:
|
||||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
send@0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
|
||||
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
mime "1.6.0"
|
||||
ms "2.1.3"
|
||||
on-finished "2.4.1"
|
||||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
serialize-javascript@^6.0.0, serialize-javascript@^6.0.1:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
|
||||
@ -8638,10 +8689,10 @@ serve-index@^1.9.1:
|
||||
mime-types "~2.1.17"
|
||||
parseurl "~1.3.2"
|
||||
|
||||
serve-static@1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
|
||||
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
|
||||
serve-static@1.16.0:
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92"
|
||||
integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
@ -8704,7 +8755,7 @@ shell-quote@^1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
|
||||
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
|
||||
|
||||
side-channel@^1.0.4:
|
||||
side-channel@^1.0.4, side-channel@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
|
||||
@ -8956,7 +9007,16 @@ streamroller@^3.1.5:
|
||||
debug "^4.3.4"
|
||||
fs-extra "^8.1.0"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
@ -8993,7 +9053,7 @@ string_decoder@~1.1.1:
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
@ -9007,6 +9067,13 @@ strip-ansi@^3.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^7.0.1:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
|
||||
@ -9269,10 +9336,10 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.6.2:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
|
||||
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.7.0:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
|
||||
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
@ -9781,7 +9848,7 @@ word-wrap@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
@ -9799,6 +9866,15 @@ wrap-ansi@^6.2.0:
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
|
||||
|
@ -1 +0,0 @@
|
||||
You have to install Pylon as described in [their documentation](https://pylon.cronit.io/docs/installation/).
|
@ -6,7 +6,6 @@ sidebar_label: Pylon
|
||||
import AppJWT from "../imports/_app_jwt.mdx";
|
||||
import ServiceuserJWT from "../imports/_serviceuser_jwt.mdx";
|
||||
import ServiceuserRole from "../imports/_serviceuser_role.mdx";
|
||||
import SetupPylon from "../imports/_setup_pylon.mdx";
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your [Pylon](https://pylon.cronit.io) service.
|
||||
It explains how to check the token validity in the API and how to check for permissions.
|
||||
@ -43,26 +42,27 @@ And the following from the Serviceuser:
|
||||
|
||||
## Setup new Pylon service
|
||||
|
||||
### Setup Pylon
|
||||
Pylon allows you to create a new service using the `npm create pylon` command. This command creates a new Pylon project with a basic project structure and configuration.
|
||||
During the setup process, you can choose your preferred runtime, such as Bun, Node.js, or Cloudflare Workers.
|
||||
|
||||
<SetupPylon />
|
||||
**This guide uses the Bun runtime.**
|
||||
|
||||
### Creating a new project
|
||||
|
||||
To create a new Pylon project, run the following command:
|
||||
|
||||
```bash
|
||||
pylon new my-pylon-project
|
||||
npm create pylon my-pylon@latest
|
||||
```
|
||||
|
||||
This will create a new directory called `my-pylon-project` with a basic Pylon project structure.
|
||||
This will create a new directory called `my-pylon` with a basic Pylon project structure.
|
||||
|
||||
### Project structure
|
||||
|
||||
Pylon projects are structured as follows:
|
||||
|
||||
```
|
||||
my-pylon-project/
|
||||
my-pylon/
|
||||
├── .pylon/
|
||||
├── src/
|
||||
│ ├── index.ts
|
||||
@ -81,16 +81,18 @@ my-pylon-project/
|
||||
Here's an example of a basic Pylon service:
|
||||
|
||||
```ts
|
||||
import { defineService } from "@getcronit/pylon";
|
||||
import { app } from "@getcronit/pylon";
|
||||
|
||||
export default defineService({
|
||||
export const graphql = {
|
||||
Query: {
|
||||
sum: (a: number, b: number) => a + b,
|
||||
},
|
||||
Mutation: {
|
||||
divide: (a: number, b: number) => a / b,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
## Secure the API
|
||||
@ -113,6 +115,8 @@ AUTH_PROJECT_ID='250719519163548112'
|
||||
|
||||
2. Copy the `.json`-key-file that you downloaded from the ZITADEL Console into the root folder of your project and rename it to `key.json`.
|
||||
|
||||
3. (Optional) For added convenience in production environments, you can include the content of the .json key file as `AUTH_KEY` in the .env file or as an environment variable.
|
||||
|
||||
### Auth
|
||||
|
||||
Pylon provides a auth module and a decorator to check the validity of the token and the permissions.
|
||||
@ -140,8 +144,7 @@ The following code demonstrates how to create a Pylon service with the required
|
||||
|
||||
```ts
|
||||
import {
|
||||
defineService,
|
||||
PylonAPI,
|
||||
app,
|
||||
auth,
|
||||
requireAuth,
|
||||
getContext,
|
||||
@ -208,7 +211,7 @@ class User {
|
||||
}
|
||||
}
|
||||
|
||||
export default defineService({
|
||||
export const graphql = {
|
||||
Query: {
|
||||
me: User.me,
|
||||
info: () => "Public Data",
|
||||
@ -216,43 +219,43 @@ export default defineService({
|
||||
Mutation: {
|
||||
createUser: User.create,
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize the authentication middleware
|
||||
app.use("*", auth.initialize());
|
||||
|
||||
// Automatically try to create a user for each request for demonstration purposes
|
||||
app.use(async (_, next) => {
|
||||
try {
|
||||
await User.create();
|
||||
} catch {
|
||||
// Ignore errors
|
||||
// Fail silently if the user already exists
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
export const configureApp: PylonAPI["configureApp"] = (app) => {
|
||||
// Initialize the authentication middleware
|
||||
app.use("*", auth.initialize());
|
||||
app.get("/api/info", (c) => {
|
||||
return new Response("Public Data");
|
||||
});
|
||||
|
||||
// Automatically try to create a user for each request for demonstration purposes
|
||||
app.use(async (_, next) => {
|
||||
try {
|
||||
await User.create();
|
||||
} catch {
|
||||
// Ignore errors
|
||||
// Fail silently if the user already exists
|
||||
}
|
||||
// The `auth.require()` middleware is optional here, as the `User.me` method already checks for it.
|
||||
app.get("/api/me", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
|
||||
await next();
|
||||
});
|
||||
return c.json(user);
|
||||
});
|
||||
|
||||
app.get("/api/info", (c) => {
|
||||
return new Response("Public Data");
|
||||
});
|
||||
// A role check for `read:messages` is not required here, as the `user.messages` method already checks for it.
|
||||
app.get("/api/me/messages", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
|
||||
// The `auth.require()` middleware is optional here, as the `User.me` method already checks for it.
|
||||
app.get("/api/me", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
// This will throw an error if the user does not have the `read:messages` role
|
||||
return c.json(await user.messages());
|
||||
});
|
||||
|
||||
return c.json(user);
|
||||
});
|
||||
|
||||
// A role check for `read:messages` is not required here, as the `user.messages` method already checks for it.
|
||||
app.get("/api/me/messages", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
|
||||
// This will throw an error if the user does not have the `read:messages` role
|
||||
return c.json(await user.messages());
|
||||
});
|
||||
};
|
||||
export default app;
|
||||
```
|
||||
|
||||
### Call the API
|
||||
@ -273,7 +276,7 @@ export TOKEN='MtjHodGy4zxKylDOhg6kW90WeEQs2q...'
|
||||
Now you have to start the Pylon service:
|
||||
|
||||
```bash
|
||||
bun run develop
|
||||
bun run dev
|
||||
```
|
||||
|
||||
With the access token, you can then do the following calls:
|
||||
|
166
docs/docs/guides/manage/customize/notification-providers.mdx
Normal file
166
docs/docs/guides/manage/customize/notification-providers.mdx
Normal file
@ -0,0 +1,166 @@
|
||||
---
|
||||
title: SMS, SMTP and HTTP Provider for Notifications
|
||||
sidebar_label: Notification Providers
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
ZITADEL can send messages to users via different notification providers, such as SMS, SMTP, or Webhook (HTTP Provider).
|
||||
While you can add multiple providers to different channels, messages will only be delivered via the actived provider.
|
||||
Message and notification texts can be [customized](./texts) for an instance or for each organization.
|
||||
|
||||
## SMS providers
|
||||
|
||||
ZITADEL integrates with Twilio as SMS provider.
|
||||
|
||||
## SMTP providers
|
||||
|
||||
Integration with most SMTP providers is possible through a generic SMTP provider template that allows you to configure custom SMTP providers.
|
||||
Additionally, integration templates are available for:
|
||||
|
||||
- Amazon SES
|
||||
- Mailgun
|
||||
- Mailjet
|
||||
- Postmark
|
||||
- Sendgrid
|
||||
|
||||
:::info Default Provider ZITADEL Cloud
|
||||
A default SMTP provider is configured for ZITADEL Cloud customers.
|
||||
This provider meant for development and testing purposes and you must replace this provider with your custom SMTP provider for production use cases to guarantee security and reliability of your service.
|
||||
:::
|
||||
|
||||
## Webhook / HTTP provider
|
||||
|
||||
Webhook (HTTP Provider) allows you to fully customize the messages and use integrate with any provider or custom solution to deliver the messages to users.
|
||||
A provider with HTTP type will send the messages and the data to a pre-defined webhook as JSON.
|
||||
|
||||
### Configuring a HTTP provider
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="sms" label="SMS" default>
|
||||
|
||||
First [add a new SMS Provider of type HTTP](/apis/resources/admin/admin-service-add-sms-provider-http) to create a new HTTP provider that can be used to send SMS messages:
|
||||
|
||||
```bash
|
||||
curl -L 'https://$CUSTOM-DOMAIN/admin/v1/sms/http' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Authorization: Bearer <TOKEN>' \
|
||||
-d '{
|
||||
"endpoint": "http://relay.example.com/provider",
|
||||
"description": "provider description"
|
||||
}'
|
||||
```
|
||||
|
||||
Where `endpoint` defines the Webhook endpoint to which the data should be sent to.
|
||||
The result will contain an ID of the provider that we need in the next step.
|
||||
|
||||
You can configure multiple SMS providers at the same time.
|
||||
To use the HTTP provider you need to [activate the SMS provider](/apis/resources/admin/admin-service-activate-sms-provider):
|
||||
|
||||
```bash
|
||||
curl -L 'https://$CUSTOM-DOMAIN/admin/v1/sms/:id/_activate' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Authorization: Bearer <TOKEN>' \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
The `id` is the provider's ID from the previous step.
|
||||
|
||||
See full API reference for [SMS Providers](/apis/resources/admin/sms-provider) for more details.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="email" label="Email">
|
||||
|
||||
First [add a new Email Provider of type HTTP](/apis/resources/admin/admin-service-add-email-provider-http) to create a new HTTP provider that can be used to send SMS messages:
|
||||
|
||||
```bash
|
||||
curl -L 'https://$CUSTOM-DOMAIN/admin/v1/email/http' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Authorization: Bearer <TOKEN>' \
|
||||
-d '{
|
||||
"endpoint": "http://relay.example.com/provider",
|
||||
"description": "provider description"
|
||||
}'
|
||||
```
|
||||
|
||||
Where `endpoint` defines the Webhook endpoint to which the data should be sent to.
|
||||
The result will contain an ID of the provider that we need in the next step.
|
||||
|
||||
You can configure multiple Email providers at the same time.
|
||||
To use the HTTP provider you need to [activate the Email provider](/apis/resources/admin/admin-service-activate-email-provider):
|
||||
|
||||
```bash
|
||||
curl -L 'https://$CUSTOM-DOMAIN/admin/v1/email/:id/_activate' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Authorization: Bearer <TOKEN>' \
|
||||
-d '{}'
|
||||
```
|
||||
|
||||
The `id` is the provider's ID from the previous step.
|
||||
|
||||
See full API reference for [Email Providers](/apis/resources/admin/admin-service-list-email-providers) for more details.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### HTTP provider payload
|
||||
|
||||
In case of the Twilio and Email providers, the messages will be sent as before, in case of the HTTP providers the content of the messages is the same but as a HTTP call.
|
||||
|
||||
Here an example of the body of an payload sent via Email HTTP provider:
|
||||
|
||||
```json
|
||||
{
|
||||
"contextInfo": {
|
||||
"eventType": "user.human.initialization.code.added",
|
||||
"provider": {
|
||||
"id": "285181292935381355",
|
||||
"description": "test"
|
||||
},
|
||||
"recipientEmailAddress": "example@zitadel.com"
|
||||
},
|
||||
"templateData": {
|
||||
"title": "Zitadel - Initialize User",
|
||||
"preHeader": "Initialize User",
|
||||
"subject": "Initialize User",
|
||||
"greeting": "Hello GivenName FamilyName,",
|
||||
"text": "This user was created in Zitadel. Use the username Username to login. Please click the button below to finish the initialization process. (Code 0M53RF) If you didn't ask for this mail, please ignore it.",
|
||||
"url": "http://example.zitadel.com/ui/login/user/init?authRequestID=\u0026code=0M53RF\u0026loginname=Username\u0026orgID=275353657317327214\u0026passwordset=false\u0026userID=285181014567813483",
|
||||
"buttonText": "Finish initialization",
|
||||
"primaryColor": "#5469d4",
|
||||
"backgroundColor": "#fafafa",
|
||||
"fontColor": "#000000",
|
||||
"fontFamily": "-apple-system, BlinkMacSystemFont, Segoe UI, Lato, Arial, Helvetica, sans-serif",
|
||||
"footerText": "InitCode.Footer"
|
||||
},
|
||||
"args": {
|
||||
"changeDate": "2024-09-16T10:58:50.73237+02:00",
|
||||
"code": "0M53RF",
|
||||
"creationDate": "2024-09-16T10:58:50.73237+02:00",
|
||||
"displayName": "GivenName FamilyName",
|
||||
"firstName": "GivenName",
|
||||
"lastEmail": "example@zitadel.com",
|
||||
"lastName": "FamilyName",
|
||||
"lastPhone": "+41791234567",
|
||||
"loginNames": [
|
||||
"Username"
|
||||
],
|
||||
"nickName": "",
|
||||
"preferredLoginName": "Username",
|
||||
"userName": "Username",
|
||||
"verifiedEmail": "example@zitadel.com",
|
||||
"verifiedPhone": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are 3 elements to this message:
|
||||
|
||||
- `contextInfo`, with information on why this message is sent like the Event, which Email or SMS provider is used and which recipient should receive this message
|
||||
- `templateData`, with all texts and format information which can be used with a template to produce the desired message
|
||||
- `args`, with the information provided to the user which can be used in the message to customize
|
@ -1,74 +0,0 @@
|
||||
---
|
||||
title: SMS, SMTP and HTTP Provider for Notifications
|
||||
---
|
||||
|
||||
All Notifications send as SMS and Email are customizable as that you can define your own providers,
|
||||
which then send the notifications out. These providers can also be defined as an HTTP type,
|
||||
and the text and content, which is used to send the SMS's and Emails will get send to a Webhook as JSON.
|
||||
|
||||
With this everything can be customized or even custom logic can be implemented to use a not yet supported provider by ZITADEL.
|
||||
|
||||
## How it works
|
||||
|
||||
There is a default provider configured in ZITADEL Cloud, both for SMS's and Emails, but this default providers can be changed through the respective API's.
|
||||
|
||||
This API's are provided on an instance level:
|
||||
- [SMS Providers](/apis/resources/admin/sms-provider)
|
||||
- [Email Providers](/apis/resources/admin/email-provider)
|
||||
|
||||
To use a non-default provider just add, and then activate. There can only be 1 provider be activated at the same time.
|
||||
|
||||
## Resulting messages
|
||||
|
||||
In case of the Twilio and SMTP providers, the messages will be sent as before, in case of the HTTP providers the content of the messages is the same but as a HTTP call.
|
||||
|
||||
Here an example of the body of an Email sent via HTTP provider:
|
||||
```json
|
||||
{
|
||||
"contextInfo": {
|
||||
"eventType": "user.human.initialization.code.added",
|
||||
"provider": {
|
||||
"id": "285181292935381355",
|
||||
"description": "test"
|
||||
},
|
||||
"recipientEmailAddress": "example@zitadel.com"
|
||||
},
|
||||
"templateData": {
|
||||
"title": "Zitadel - Initialize User",
|
||||
"preHeader": "Initialize User",
|
||||
"subject": "Initialize User",
|
||||
"greeting": "Hello GivenName FamilyName,",
|
||||
"text": "This user was created in Zitadel. Use the username Username to login. Please click the button below to finish the initialization process. (Code 0M53RF) If you didn't ask for this mail, please ignore it.",
|
||||
"url": "http://example.zitadel.com/ui/login/user/init?authRequestID=\u0026code=0M53RF\u0026loginname=Username\u0026orgID=275353657317327214\u0026passwordset=false\u0026userID=285181014567813483",
|
||||
"buttonText": "Finish initialization",
|
||||
"primaryColor": "#5469d4",
|
||||
"backgroundColor": "#fafafa",
|
||||
"fontColor": "#000000",
|
||||
"fontFamily": "-apple-system, BlinkMacSystemFont, Segoe UI, Lato, Arial, Helvetica, sans-serif",
|
||||
"footerText": "InitCode.Footer"
|
||||
},
|
||||
"args": {
|
||||
"changeDate": "2024-09-16T10:58:50.73237+02:00",
|
||||
"code": "0M53RF",
|
||||
"creationDate": "2024-09-16T10:58:50.73237+02:00",
|
||||
"displayName": "GivenName FamilyName",
|
||||
"firstName": "GivenName",
|
||||
"lastEmail": "example@zitadel.com",
|
||||
"lastName": "FamilyName",
|
||||
"lastPhone": "+41791234567",
|
||||
"loginNames": [
|
||||
"Username"
|
||||
],
|
||||
"nickName": "",
|
||||
"preferredLoginName": "Username",
|
||||
"userName": "Username",
|
||||
"verifiedEmail": "example@zitadel.com",
|
||||
"verifiedPhone": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
There are 3 elements to this message:
|
||||
- contextInfo, with information on why this message is sent like the Event, which Email or SMS provider is used and which recipient should receive this message
|
||||
- templateData, with all texts and format information which can be used with a template to produce the desired message
|
||||
- args, with the information provided to the user which can be used in the message to customize
|
@ -187,7 +187,7 @@ module.exports = {
|
||||
selector: "div#",
|
||||
},
|
||||
prism: {
|
||||
additionalLanguages: ["csharp", "dart", "groovy", "regex", "java", "php", "python", "protobuf"],
|
||||
additionalLanguages: ["csharp", "dart", "groovy", "regex", "java", "php", "python", "protobuf", "json", "bash"],
|
||||
},
|
||||
colorMode: {
|
||||
defaultMode: "dark",
|
||||
|
@ -154,11 +154,10 @@ module.exports = {
|
||||
type: "category",
|
||||
label: "Customize",
|
||||
items: [
|
||||
"guides/manage/customize/branding",
|
||||
"guides/manage/customize/texts",
|
||||
"guides/manage/customize/behavior",
|
||||
"guides/manage/customize/restrictions",
|
||||
"guides/manage/customize/notifications",
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "guides/manage/customize",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -55,5 +55,6 @@ func UserGrantToPb(grant *query.UserGrant) *auth_pb.UserGrant {
|
||||
ProjectGrantId: grant.GrantID,
|
||||
RoleKeys: grant.Roles,
|
||||
UserType: user.TypeToPb(grant.UserType),
|
||||
State: user.UserGrantStateToPb(grant.State),
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ func UserGrantToPb(assetPrefix string, grant *query.UserGrant) *user_pb.UserGran
|
||||
return &user_pb.UserGrant{
|
||||
Id: grant.ID,
|
||||
UserId: grant.UserID,
|
||||
State: user_pb.UserGrantState_USER_GRANT_STATE_ACTIVE,
|
||||
State: UserGrantStateToPb(grant.State),
|
||||
RoleKeys: grant.Roles,
|
||||
ProjectId: grant.ProjectID,
|
||||
OrgId: grant.ResourceOwner,
|
||||
@ -51,6 +51,21 @@ func UserGrantToPb(assetPrefix string, grant *query.UserGrant) *user_pb.UserGran
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantStateToPb(state domain.UserGrantState) user_pb.UserGrantState {
|
||||
switch state {
|
||||
case domain.UserGrantStateActive:
|
||||
return user_pb.UserGrantState_USER_GRANT_STATE_ACTIVE
|
||||
case domain.UserGrantStateInactive:
|
||||
return user_pb.UserGrantState_USER_GRANT_STATE_INACTIVE
|
||||
case domain.UserGrantStateRemoved,
|
||||
domain.UserGrantStateUnspecified:
|
||||
// these states should never occur here and are mainly listed for linting purposes
|
||||
fallthrough
|
||||
default:
|
||||
return user_pb.UserGrantState_USER_GRANT_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantQueriesToQuery(ctx context.Context, queries []*user_pb.UserGrantQuery) (q []query.SearchQuery, err error) {
|
||||
q = make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
|
@ -330,6 +330,9 @@ func (o *OPStorage) setUserinfo(ctx context.Context, userInfo *oidc.UserInfo, us
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if user.State != domain.UserStateActive {
|
||||
return zerrors.ThrowUnauthenticated(nil, "OIDC-S3tha", "Errors.Users.NotActive")
|
||||
}
|
||||
var allRoles bool
|
||||
roles := make([]string, 0)
|
||||
for _, scope := range scopes {
|
||||
@ -799,19 +802,24 @@ func (o *OPStorage) assertRoles(ctx context.Context, userID, applicationID strin
|
||||
if projectID != "" {
|
||||
roleAudience = append(roleAudience, projectID)
|
||||
}
|
||||
queries := make([]query.SearchQuery, 0, 2)
|
||||
projectQuery, err := query.NewUserGrantProjectIDsSearchQuery(roleAudience)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
queries = append(queries, projectQuery)
|
||||
userIDQuery, err := query.NewUserGrantUserIDSearchQuery(userID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
queries = append(queries, userIDQuery)
|
||||
activeQuery, err := query.NewUserGrantStateQuery(domain.UserGrantStateActive)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
grants, err := o.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: queries,
|
||||
Queries: []query.SearchQuery{
|
||||
projectQuery,
|
||||
userIDQuery,
|
||||
activeQuery,
|
||||
},
|
||||
}, true)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -24,6 +24,9 @@ func TestServer_ClientCredentialsExchange(t *testing.T) {
|
||||
machine, name, clientID, clientSecret, err := Instance.CreateOIDCCredentialsClient(CTX)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, clientIDInactive, clientSecretInactive, err := Instance.CreateOIDCCredentialsClientInactive(CTX)
|
||||
require.NoError(t, err)
|
||||
|
||||
type claims struct {
|
||||
name string
|
||||
username string
|
||||
@ -71,6 +74,13 @@ func TestServer_ClientCredentialsExchange(t *testing.T) {
|
||||
scope: []string{oidc.ScopeOpenID},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "inactive machine user error",
|
||||
clientID: clientIDInactive,
|
||||
clientSecret: clientSecretInactive,
|
||||
scope: []string{oidc.ScopeOpenID},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "wrong secret error",
|
||||
clientID: clientID,
|
||||
|
@ -66,7 +66,10 @@ func (s *Server) UserInfo(ctx context.Context, r *op.Request[oidc.UserInfoReques
|
||||
false,
|
||||
)(ctx, true, domain.TriggerTypePreUserinfoCreation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
return nil, op.NewStatusError(oidc.ErrAccessDenied().WithDescription("no active user").WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError), http.StatusUnauthorized)
|
||||
}
|
||||
return op.NewResponse(userInfo), nil
|
||||
}
|
||||
|
@ -131,6 +131,9 @@ func (p *Storage) SetUserinfoWithUserID(ctx context.Context, applicationID strin
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if user.State != domain.UserStateActive {
|
||||
return zerrors.ThrowPreconditionFailed(nil, "SAML-S3gFd", "Errors.User.NotActive")
|
||||
}
|
||||
|
||||
userGrants, err := p.getGrants(ctx, userID, applicationID)
|
||||
if err != nil {
|
||||
@ -157,6 +160,9 @@ func (p *Storage) SetUserinfoWithLoginName(ctx context.Context, userinfo models.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if user.State != domain.UserStateActive {
|
||||
return zerrors.ThrowPreconditionFailed(nil, "SAML-FJ262", "Errors.User.NotActive")
|
||||
}
|
||||
|
||||
setUserinfo(user, userinfo, attributes, map[string]*customAttribute{})
|
||||
return nil
|
||||
@ -324,10 +330,15 @@ func (p *Storage) getGrants(ctx context.Context, userID, applicationID string) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
activeQuery, err := query.NewUserGrantStateQuery(domain.UserGrantStateActive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.query.UserGrants(ctx, &query.UserGrantsQueries{
|
||||
Queries: []query.SearchQuery{
|
||||
projectQuery,
|
||||
userIDQuery,
|
||||
activeQuery,
|
||||
},
|
||||
}, true)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
eventstore2 "github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -119,7 +120,11 @@ func (q queryViewWrapper) UserGrantsByProjectAndUserID(ctx context.Context, proj
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID, userGrantProjectID}}
|
||||
activeQuery, err := query.NewUserGrantStateQuery(domain.UserGrantStateActive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries := &query.UserGrantsQueries{Queries: []query.SearchQuery{userGrantUserID, userGrantProjectID, activeQuery}}
|
||||
grants, err := q.Queries.UserGrants(ctx, queries, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -144,7 +144,7 @@ func (c *Commands) CreateOIDCSessionFromDeviceAuth(ctx context.Context, deviceCo
|
||||
return nil, DeviceAuthStateError(deviceAuthModel.State)
|
||||
}
|
||||
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, deviceAuthModel.UserOrgID)
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, deviceAuthModel.UserID, deviceAuthModel.UserOrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
pushErr := errors.New("pushErr")
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@ -149,7 +149,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
@ -169,7 +169,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "push error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
@ -211,7 +211,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "success",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
@ -256,7 +256,7 @@ func TestCommands_ApproveDeviceAuth(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
gotDetails, err := c.ApproveDeviceAuth(tt.args.ctx, tt.args.id, tt.args.userID, tt.args.userOrgID, tt.args.authMethods, tt.args.authTime, tt.args.preferredLanguage, tt.args.userAgent, tt.args.sessionID)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
@ -271,7 +271,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
pushErr := errors.New("pushErr")
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@ -288,7 +288,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
@ -298,7 +298,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "push error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
@ -323,7 +323,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "success/denied",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
@ -350,7 +350,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
{
|
||||
name: "success/expired",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
@ -378,7 +378,7 @@ func TestCommands_CancelDeviceAuth(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
gotDetails, err := c.CancelDeviceAuth(tt.args.ctx, tt.args.id, tt.args.reason)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
@ -586,6 +586,69 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
},
|
||||
wantErr: DeviceAuthStateError(domain.DeviceAuthStateDone),
|
||||
},
|
||||
{
|
||||
name: "user not active",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewAddedEvent(
|
||||
ctx,
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"clientID", "123", "456", time.Now().Add(-time.Minute),
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"}, false,
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
deviceauth.NewApprovedEvent(ctx,
|
||||
deviceauth.NewAggregate("123", "instance1"),
|
||||
"userID", "org1",
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
testNow, &language.Afrikaans, &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
"sessionID",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
ctx,
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
user.NewUserDeactivatedEvent(
|
||||
ctx,
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
idGenerator: mock.NewIDGeneratorExpectIDs(t),
|
||||
defaultAccessTokenLifetime: time.Hour,
|
||||
defaultRefreshTokenLifetime: 7 * 24 * time.Hour,
|
||||
defaultRefreshTokenIdleLifetime: 24 * time.Hour,
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx,
|
||||
"123",
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "OIDCS-kj3g2", "Errors.User.NotActive"),
|
||||
},
|
||||
{
|
||||
name: "approved, success",
|
||||
fields: fields{
|
||||
@ -617,6 +680,21 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
ctx,
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -699,6 +777,21 @@ func TestCommands_CreateOIDCSessionFromDeviceAuth(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
ctx,
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.English,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
|
@ -80,7 +80,7 @@ func (c *Commands) CreateOIDCSessionFromAuthRequest(ctx context.Context, authReq
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, sessionModel.UserResourceOwner)
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, sessionModel.UserID, sessionModel.UserResourceOwner)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@ -141,7 +141,7 @@ func (c *Commands) CreateOIDCSession(ctx context.Context,
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, resourceOwner)
|
||||
cmd, err := c.newOIDCSessionAddEvents(ctx, userID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -265,7 +265,14 @@ func (c *Commands) RevokeOIDCSessionToken(ctx context.Context, token, clientID s
|
||||
return c.pushAppendAndReduce(ctx, writeModel, oidcsession.NewAccessTokenRevokedEvent(ctx, writeModel.aggregate))
|
||||
}
|
||||
|
||||
func (c *Commands) newOIDCSessionAddEvents(ctx context.Context, resourceOwner string, pending ...eventstore.Command) (*OIDCSessionEvents, error) {
|
||||
func (c *Commands) newOIDCSessionAddEvents(ctx context.Context, userID, resourceOwner string, pending ...eventstore.Command) (*OIDCSessionEvents, error) {
|
||||
userStateModel, err := c.userStateWriteModel(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !userStateModel.UserState.IsEnabled() {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDCS-kj3g2", "Errors.User.NotActive")
|
||||
}
|
||||
accessTokenLifetime, refreshTokenLifeTime, refreshTokenIdleLifetime, err := c.tokenTokenLifetimes(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -281,6 +288,7 @@ func (c *Commands) newOIDCSessionAddEvents(ctx context.Context, resourceOwner st
|
||||
encryptionAlg: c.keyAlgorithm,
|
||||
events: pending,
|
||||
oidcSessionWriteModel: NewOIDCSessionWriteModel(sessionID, resourceOwner),
|
||||
userStateModel: userStateModel,
|
||||
accessTokenLifetime: accessTokenLifetime,
|
||||
refreshTokenLifeTime: refreshTokenLifeTime,
|
||||
refreshTokenIdleLifetime: refreshTokenIdleLifetime,
|
||||
@ -321,6 +329,13 @@ func (c *Commands) newOIDCSessionUpdateEvents(ctx context.Context, refreshToken
|
||||
if err = sessionWriteModel.CheckRefreshToken(refreshTokenID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userStateWriteModel, err := c.userStateWriteModel(ctx, sessionWriteModel.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !userStateWriteModel.UserState.IsEnabled() {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDCS-J39h2", "Errors.User.NotActive")
|
||||
}
|
||||
accessTokenLifetime, refreshTokenLifeTime, refreshTokenIdleLifetime, err := c.tokenTokenLifetimes(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -342,6 +357,7 @@ type OIDCSessionEvents struct {
|
||||
encryptionAlg crypto.EncryptionAlgorithm
|
||||
events []eventstore.Command
|
||||
oidcSessionWriteModel *OIDCSessionWriteModel
|
||||
userStateModel *UserV2WriteModel
|
||||
|
||||
accessTokenLifetime time.Duration
|
||||
refreshTokenLifeTime time.Duration
|
||||
|
@ -205,6 +205,103 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"user not active",
|
||||
fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
authrequest.NewAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate,
|
||||
"loginClient",
|
||||
"clientID",
|
||||
"redirectURI",
|
||||
"state",
|
||||
"nonce",
|
||||
[]string{"openid", "offline_access"},
|
||||
[]string{"audience"},
|
||||
domain.OIDCResponseTypeCode,
|
||||
domain.OIDCResponseModeQuery,
|
||||
&domain.OIDCCodeChallenge{
|
||||
Challenge: "challenge",
|
||||
Method: domain.CodeChallengeMethodS256,
|
||||
},
|
||||
[]domain.Prompt{domain.PromptNone},
|
||||
[]string{"en", "de"},
|
||||
gu.Ptr(time.Duration(0)),
|
||||
gu.Ptr("loginHint"),
|
||||
gu.Ptr("hintUserID"),
|
||||
true,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
authrequest.NewCodeAddedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
authrequest.NewSessionLinkedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate,
|
||||
"sessionID",
|
||||
"userID",
|
||||
testNow,
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
session.NewAddedEvent(context.Background(),
|
||||
&session.NewAggregate("sessionID", "instance1").Aggregate,
|
||||
&domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewUserCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate,
|
||||
"userID", "org1", testNow, &language.Afrikaans),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
session.NewPasswordCheckedEvent(context.Background(), &session.NewAggregate("sessionID", "instanceID").Aggregate,
|
||||
testNow),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
user.NewUserDeactivatedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
idGenerator: mock.NewIDGeneratorExpectIDs(t),
|
||||
defaultAccessTokenLifetime: time.Hour,
|
||||
defaultRefreshTokenLifetime: 7 * 24 * time.Hour,
|
||||
defaultRefreshTokenIdleLifetime: 24 * time.Hour,
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
authRequestID: "V2_authRequestID",
|
||||
complianceCheck: mockAuthRequestComplianceChecker(nil),
|
||||
needRefreshToken: true,
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowPreconditionFailed(nil, "OIDCS-kj3g2", "Errors.User.NotActive"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"add successful",
|
||||
fields{
|
||||
@ -266,6 +363,21 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
testNow),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
authrequest.NewCodeExchangedEvent(context.Background(), &authrequest.NewAggregate("V2_authRequestID", "instanceID").Aggregate),
|
||||
@ -382,6 +494,21 @@ func TestCommands_CreateOIDCSessionFromAuthRequest(t *testing.T) {
|
||||
testNow),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -521,10 +648,81 @@ func TestCommands_CreateOIDCSession(t *testing.T) {
|
||||
},
|
||||
wantErr: io.ErrClosedPipe,
|
||||
},
|
||||
{
|
||||
name: "not active user",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
user.NewUserDeactivatedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
idGenerator: mock.NewIDGeneratorExpectIDs(t),
|
||||
defaultAccessTokenLifetime: time.Hour,
|
||||
defaultRefreshTokenLifetime: 7 * 24 * time.Hour,
|
||||
defaultRefreshTokenIdleLifetime: 24 * time.Hour,
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
resourceOwner: "org1",
|
||||
clientID: "clientID",
|
||||
audience: []string{"audience"},
|
||||
scope: []string{"openid", "offline_access"},
|
||||
authMethods: []domain.UserAuthMethodType{domain.UserAuthMethodTypePassword},
|
||||
authTime: testNow,
|
||||
nonce: "nonce",
|
||||
preferredLanguage: &language.Afrikaans,
|
||||
userAgent: &domain.UserAgent{
|
||||
FingerprintID: gu.Ptr("fp1"),
|
||||
IP: net.ParseIP("1.2.3.4"),
|
||||
Description: gu.Ptr("firefox"),
|
||||
Header: http.Header{"foo": []string{"bar"}},
|
||||
},
|
||||
reason: domain.TokenReasonAuthRequest,
|
||||
actor: &domain.TokenActor{
|
||||
UserID: "user2",
|
||||
Issuer: "foo.com",
|
||||
},
|
||||
needRefreshToken: false,
|
||||
},
|
||||
wantErr: zerrors.ThrowPreconditionFailed(nil, "OIDCS-kj3g2", "Errors.User.NotActive"),
|
||||
},
|
||||
{
|
||||
name: "without refresh token",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -606,6 +804,21 @@ func TestCommands_CreateOIDCSession(t *testing.T) {
|
||||
name: "with refresh token",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -689,6 +902,21 @@ func TestCommands_CreateOIDCSession(t *testing.T) {
|
||||
name: "with sessionID",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -772,6 +1000,21 @@ func TestCommands_CreateOIDCSession(t *testing.T) {
|
||||
name: "impersonation not allowed",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
),
|
||||
idGenerator: mock.NewIDGeneratorExpectIDs(t, "oidcSessionID"),
|
||||
@ -813,6 +1056,21 @@ func TestCommands_CreateOIDCSession(t *testing.T) {
|
||||
name: "impersonation allowed",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
user.NewUserImpersonatedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate, "clientID", &domain.TokenActor{
|
||||
@ -1067,6 +1325,63 @@ func TestCommands_ExchangeOIDCSessionRefreshAndAccessToken(t *testing.T) {
|
||||
err: zerrors.ThrowPreconditionFailed(nil, "OIDCS-3jt2w", "Errors.OIDCSession.RefreshTokenInvalid"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"user not active",
|
||||
fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
"userID", "org1", "sessionID", "clientID", []string{"audience"}, []string{"openid", "profile", "offline_access"},
|
||||
[]domain.UserAuthMethodType{domain.UserAuthMethodTypePassword}, testNow, "nonce", &language.Afrikaans,
|
||||
&domain.UserAgent{FingerprintID: gu.Ptr("browserFP")},
|
||||
),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
"at_accessTokenID", []string{"openid", "profile", "offline_access"}, time.Hour, domain.TokenReasonAuthRequest, nil),
|
||||
),
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
oidcsession.NewRefreshTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
"rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
user.NewUserDeactivatedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
idGenerator: mock.NewIDGeneratorExpectIDs(t),
|
||||
defaultAccessTokenLifetime: time.Hour,
|
||||
defaultRefreshTokenLifetime: 7 * 24 * time.Hour,
|
||||
defaultRefreshTokenIdleLifetime: 24 * time.Hour,
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
refreshToken: "VjJfb2lkY1Nlc3Npb25JRC1ydF9yZWZyZXNoVG9rZW5JRDp1c2VySUQ", //V2_oidcSessionID:rt_refreshTokenID:userID
|
||||
scope: []string{"openid", "offline_access"},
|
||||
complianceCheck: mockRefreshTokenComplianceChecker(nil),
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowPreconditionFailed(nil, "OIDCS-J39h2", "Errors.User.NotActive"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"refresh successful",
|
||||
fields{
|
||||
@ -1088,6 +1403,21 @@ func TestCommands_ExchangeOIDCSessionRefreshAndAccessToken(t *testing.T) {
|
||||
"rt_refreshTokenID", 7*24*time.Hour, 24*time.Hour),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.Afrikaans,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
false,
|
||||
),
|
||||
),
|
||||
expectFilter(), // token lifetime
|
||||
expectPush(
|
||||
oidcsession.NewAccessTokenAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1153,7 +1483,7 @@ func TestCommands_ExchangeOIDCSessionRefreshAndAccessToken(t *testing.T) {
|
||||
|
||||
func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
defaultAccessTokenLifetime time.Duration
|
||||
defaultRefreshTokenLifetime time.Duration
|
||||
@ -1177,7 +1507,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
{
|
||||
"invalid refresh token format error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
eventstore: expectEventstore(),
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args{
|
||||
@ -1191,7 +1521,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
{
|
||||
"inactive session error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
@ -1207,7 +1537,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
{
|
||||
"invalid refresh token error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1235,7 +1565,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
{
|
||||
"expired refresh token error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1267,7 +1597,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
{
|
||||
"get successful",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusherWithCreationDateNow(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1316,7 +1646,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
defaultAccessTokenLifetime: tt.fields.defaultAccessTokenLifetime,
|
||||
defaultRefreshTokenLifetime: tt.fields.defaultRefreshTokenLifetime,
|
||||
@ -1348,7 +1678,7 @@ func TestCommands_OIDCSessionByRefreshToken(t *testing.T) {
|
||||
|
||||
func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
keyAlgorithm crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
@ -1368,7 +1698,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"invalid token",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
eventstore: expectEventstore(),
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args{
|
||||
@ -1382,7 +1712,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"refresh_token inactive",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1407,7 +1737,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"refresh_token invalid client",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1432,7 +1762,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"refresh_token revoked",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1468,7 +1798,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"access_token inactive session",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1493,7 +1823,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"access_token invalid client",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1518,7 +1848,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
{
|
||||
"access_token revoked",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
oidcsession.NewAddedEvent(context.Background(), &oidcsession.NewAggregate("V2_oidcSessionID", "org1").Aggregate,
|
||||
@ -1555,7 +1885,7 @@ func TestCommands_RevokeOIDCSessionToken(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
keyAlgorithm: tt.fields.keyAlgorithm,
|
||||
}
|
||||
err := c.RevokeOIDCSessionToken(tt.args.ctx, tt.args.token, tt.args.clientID)
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/zitadel/zitadel/pkg/grpc/authn"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/management"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user"
|
||||
user_v2 "github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||
)
|
||||
|
||||
func (i *Instance) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, appType app.OIDCAppType, authMethod app.OIDCAuthMethodType, devMode bool, grantTypes ...app.OIDCGrantType) (*management.AddOIDCAppResponse, error) {
|
||||
@ -355,6 +356,31 @@ func (i *Instance) CreateOIDCCredentialsClient(ctx context.Context) (machine *ma
|
||||
return machine, name, secret.GetClientId(), secret.GetClientSecret(), nil
|
||||
}
|
||||
|
||||
func (i *Instance) CreateOIDCCredentialsClientInactive(ctx context.Context) (machine *management.AddMachineUserResponse, name, clientID, clientSecret string, err error) {
|
||||
name = gofakeit.Username()
|
||||
machine, err = i.Client.Mgmt.AddMachineUser(ctx, &management.AddMachineUserRequest{
|
||||
Name: name,
|
||||
UserName: name,
|
||||
AccessTokenType: user.AccessTokenType_ACCESS_TOKEN_TYPE_JWT,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
secret, err := i.Client.Mgmt.GenerateMachineSecret(ctx, &management.GenerateMachineSecretRequest{
|
||||
UserId: machine.GetUserId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
_, err = i.Client.UserV2.DeactivateUser(ctx, &user_v2.DeactivateUserRequest{
|
||||
UserId: machine.GetUserId(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
return machine, name, secret.GetClientId(), secret.GetClientSecret(), nil
|
||||
}
|
||||
|
||||
func (i *Instance) CreateOIDCJWTProfileClient(ctx context.Context) (machine *management.AddMachineUserResponse, name string, keyData []byte, err error) {
|
||||
name = gofakeit.Username()
|
||||
machine, err = i.Client.Mgmt.AddMachineUser(ctx, &management.AddMachineUserRequest{
|
||||
|
@ -143,6 +143,10 @@ func NewUserGrantRoleQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(UserGrantRoles, value, TextListContains)
|
||||
}
|
||||
|
||||
func NewUserGrantStateQuery(value domain.UserGrantState) (SearchQuery, error) {
|
||||
return NewNumberQuery(UserGrantState, value, NumberEquals)
|
||||
}
|
||||
|
||||
func NewUserGrantWithGrantedQuery(owner string) (SearchQuery, error) {
|
||||
orgQuery, err := NewUserGrantResourceOwnerSearchQuery(owner)
|
||||
if err != nil {
|
||||
|
@ -2,7 +2,7 @@ with usr as (
|
||||
select u.id, u.creation_date, u.change_date, u.sequence, u.state, u.resource_owner, u.username, n.login_name as preferred_login_name
|
||||
from projections.users13 u
|
||||
left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id
|
||||
where u.id = $1
|
||||
where u.id = $1 and u.state = 1 -- only allow active users
|
||||
and u.instance_id = $2
|
||||
and n.is_primary = true
|
||||
),
|
||||
@ -38,6 +38,7 @@ user_grants as (
|
||||
where user_id = $1
|
||||
and instance_id = $2
|
||||
and project_id = any($3)
|
||||
and state = 1
|
||||
{{ if . -}}
|
||||
and resource_owner = any($4)
|
||||
{{- end }}
|
||||
|
@ -1565,6 +1565,11 @@ message UserGrant {
|
||||
description: "type of the user (human / machine)"
|
||||
}
|
||||
];
|
||||
zitadel.user.v1.UserGrantState state = 13 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "current state of the user grant";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message ListMyProjectOrgsRequest {
|
||||
|
Loading…
x
Reference in New Issue
Block a user