mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
Merge commit from fork
* feat(jwt idp): manage and validate audience * translations * fix tests * address comments * update migration version * fix merge
This commit is contained in:
@@ -61,6 +61,15 @@ the format specified in [RFC7517](https://datatracker.ietf.org/doc/html/rfc7517)
|
||||
|
||||
*Example: `https://issuer.test.internal/keys`*
|
||||
|
||||
### Audience (optional)
|
||||
|
||||
The expected audience (`aud` claim) in the JWT. If set, ZITADEL will validate that the JWT contains this audience.
|
||||
It's recommended to set this to ensure the JWT is intended to be used by ZITADEL.
|
||||
If the JWT contains multiple audiences, the configured audience must be one of them.
|
||||
If no audience is configured, ZITADEL will not validate the `aud` claim.
|
||||
|
||||
*Example: `my-client`*
|
||||
|
||||
### JWT endpoint
|
||||
|
||||
Where ZITADEL redirects users to retrieve the JWT.
|
||||
@@ -145,7 +154,7 @@ You have an existing application which exists in an internal network which handl
|
||||
application is built using ZITADEL but the userbase of the existing application needs to be able to open the new
|
||||
application from within the existing one without creating a new account or having to sign in.
|
||||
|
||||
- Existing application: `apps.test.com/existing/`
|
||||
- Existing application: `apps.test.com/existing/` (also used as audience)
|
||||
- Existing internal auth service: `issuer.test.internal`
|
||||
- New application: `new.test.com`
|
||||
- ZITADEL Login UI: `accounts.test.com`
|
||||
@@ -163,6 +172,7 @@ application from within the existing one without creating a new account or havin
|
||||
- Keys endpoint: `issuer.test.internal/keys`
|
||||
- Header name: `x-custom-tkn`
|
||||
- Issuer: `issuer.test.internal`
|
||||
- Audience: `apps.test.com/existing/`
|
||||
|
||||
#### Result flow
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ type JWT struct {
|
||||
Issuer string `json:"issuer,omitempty"`
|
||||
KeysEndpoint string `json:"keysEndpoint,omitempty"`
|
||||
HeaderName string `json:"headerName,omitempty"`
|
||||
Audience string `json:"audience,omitempty"`
|
||||
}
|
||||
|
||||
type IDPJWT struct {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 71.sql
|
||||
addJWTAudience string
|
||||
)
|
||||
|
||||
type JWTProvideAddAudienceColumn struct {
|
||||
dbClient *database.DB
|
||||
}
|
||||
|
||||
func (mig *JWTProvideAddAudienceColumn) Execute(ctx context.Context, _ eventstore.Event) error {
|
||||
_, err := mig.dbClient.ExecContext(ctx, addJWTAudience)
|
||||
return err
|
||||
}
|
||||
|
||||
func (mig *JWTProvideAddAudienceColumn) String() string {
|
||||
return "71_idp_templates6_jwt_add_audience"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE IF EXISTS projections.idp_templates6_jwt
|
||||
ADD COLUMN IF NOT EXISTS audience text;
|
||||
@@ -186,6 +186,7 @@ type Steps struct {
|
||||
s68TargetAddPayloadTypeColumn *TargetAddPayloadTypeColumn
|
||||
s69CacheTablesLogged *CacheTablesLogged
|
||||
s70AddEventStoreCommandEnforceOwner *AddEventStoreCommandEnforceOwnerColumn
|
||||
s71JWTProvideAddAudienceColumn *JWTProvideAddAudienceColumn
|
||||
RelationalTables *TransactionalTables
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s68TargetAddPayloadTypeColumn = &TargetAddPayloadTypeColumn{dbClient: dbClient}
|
||||
steps.s69CacheTablesLogged = &CacheTablesLogged{dbClient: dbClient}
|
||||
steps.s70AddEventStoreCommandEnforceOwner = &AddEventStoreCommandEnforceOwnerColumn{dbClient: dbClient}
|
||||
steps.s71JWTProvideAddAudienceColumn = &JWTProvideAddAudienceColumn{dbClient: dbClient}
|
||||
|
||||
err = projection.Create(ctx, dbClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||
if err != nil {
|
||||
@@ -372,6 +373,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
|
||||
steps.s59SetupWebkeys, // this step needs commands.
|
||||
steps.s66SessionRecoveryCodeCheckedAt,
|
||||
steps.s68TargetAddPayloadTypeColumn,
|
||||
steps.s71JWTProvideAddAudienceColumn,
|
||||
} {
|
||||
setupErr = executeMigration(ctx, eventstoreClient, step, "migration failed")
|
||||
if setupErr != nil {
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
<cnsl-label>{{ 'IDP.JWT.JWTKEYSENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="keysEndpoint" />
|
||||
</cnsl-form-field>
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.JWT.AUDIENCE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="audience" placeholder="my-client" />
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<div class="identity-provider-optional-h-wrapper">
|
||||
|
||||
@@ -117,6 +117,7 @@ export class ProviderJWTComponent {
|
||||
issuer: new UntypedFormControl('', [requiredValidator]),
|
||||
jwtEndpoint: new UntypedFormControl('', [requiredValidator]),
|
||||
keysEndpoint: new UntypedFormControl('', [requiredValidator]),
|
||||
audience: new UntypedFormControl('' ),
|
||||
});
|
||||
|
||||
this.authService
|
||||
@@ -178,6 +179,7 @@ export class ProviderJWTComponent {
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setAudience(this.audience?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
this.loading = true;
|
||||
this.service
|
||||
@@ -204,6 +206,7 @@ export class ProviderJWTComponent {
|
||||
req.setIssuer(this.issuer?.value);
|
||||
req.setJwtEndpoint(this.jwtEndpoint?.value);
|
||||
req.setKeysEndpoint(this.keysEndpoint?.value);
|
||||
req.setAudience(this.audience?.value);
|
||||
req.setProviderOptions(this.options);
|
||||
|
||||
this.loading = true;
|
||||
@@ -245,4 +248,8 @@ export class ProviderJWTComponent {
|
||||
public get keysEndpoint(): AbstractControl | null {
|
||||
return this.form.get('keysEndpoint');
|
||||
}
|
||||
|
||||
public get audience(): AbstractControl | null {
|
||||
return this.form.get('audience');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2360,7 +2360,8 @@
|
||||
"DESCRIPTION": "أدخل البيانات لمزود هوية JWT.",
|
||||
"HEADERNAME": "اسم الرأس",
|
||||
"JWTENDPOINT": "نقطة نهاية JWT",
|
||||
"JWTKEYSENDPOINT": "نقطة نهاية مفاتيح JWT"
|
||||
"JWTKEYSENDPOINT": "نقطة نهاية مفاتيح JWT",
|
||||
"AUDIENCE": "الجمهور"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "معرف الفريق",
|
||||
|
||||
@@ -2371,7 +2371,8 @@
|
||||
"DESCRIPTION": "Въведете данните за JWT Identity Provider.",
|
||||
"HEADERNAME": "Име на заглавката",
|
||||
"JWTENDPOINT": "Крайна точка на JWT",
|
||||
"JWTKEYSENDPOINT": "Крайна точка на JWT ключове"
|
||||
"JWTKEYSENDPOINT": "Крайна точка на JWT ключове",
|
||||
"AUDIENCE": "Аудитория"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Team ID",
|
||||
|
||||
@@ -2363,7 +2363,8 @@
|
||||
"DESCRIPTION": "Zadejte data pro poskytovatele identity JWT.",
|
||||
"HEADERNAME": "Název hlavičky",
|
||||
"JWTENDPOINT": "JWT koncový bod",
|
||||
"JWTKEYSENDPOINT": "Koncový bod klíčů JWT"
|
||||
"JWTKEYSENDPOINT": "Koncový bod klíčů JWT",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "ID týmu",
|
||||
|
||||
@@ -2362,7 +2362,8 @@
|
||||
"DESCRIPTION": "Geben Sie die Daten JWT Identitätsanbieter ein. ",
|
||||
"HEADERNAME": "Header Name",
|
||||
"JWTENDPOINT": "JWT Endpoint",
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Erfolgreich gespeichert.",
|
||||
|
||||
@@ -2371,7 +2371,8 @@
|
||||
"DESCRIPTION": "Enter the data for JWT Identity Provider.",
|
||||
"HEADERNAME": "Header Name",
|
||||
"JWTENDPOINT": "JWT Endpoint",
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Team ID",
|
||||
|
||||
@@ -2359,7 +2359,8 @@
|
||||
"DESCRIPTION": "Introduce los datos para el proveedor de identidad JWT.",
|
||||
"HEADERNAME": "Nombre de cabecera",
|
||||
"JWTENDPOINT": "JWT Endpoint",
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Guardado con éxito.",
|
||||
|
||||
@@ -2363,7 +2363,8 @@
|
||||
"DESCRIPTION": "Entrez les données pour le fournisseur d'identité JWT.",
|
||||
"HEADERNAME": "Nom de l'en-tête",
|
||||
"JWTENDPOINT": "Point de terminaison JWT",
|
||||
"JWTKEYSENDPOINT": "Point de terminaison des clés JWT"
|
||||
"JWTKEYSENDPOINT": "Point de terminaison des clés JWT",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Enregistré avec succès.",
|
||||
|
||||
@@ -2364,7 +2364,8 @@
|
||||
"DESCRIPTION": "Add meg az adatokat a JWT azonosítószolgáltatóhoz.",
|
||||
"HEADERNAME": "Fejléc neve",
|
||||
"JWTENDPOINT": "JWT végpont",
|
||||
"JWTKEYSENDPOINT": "JWT kulcsok végpont"
|
||||
"JWTKEYSENDPOINT": "JWT kulcsok végpont",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Csapatazonosító",
|
||||
|
||||
@@ -2364,7 +2364,8 @@
|
||||
"DESCRIPTION": "Masukkan data Penyedia Identitas JWT.",
|
||||
"HEADERNAME": "Nama Tajuk",
|
||||
"JWTENDPOINT": "Titik Akhir JWT",
|
||||
"JWTKEYSENDPOINT": "Titik Akhir Kunci JWT"
|
||||
"JWTKEYSENDPOINT": "Titik Akhir Kunci JWT",
|
||||
"AUDIENCE": "Audiens"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "ID tim",
|
||||
|
||||
@@ -2363,7 +2363,8 @@
|
||||
"DESCRIPTION": "Inserisci i dati per il JWT Identity Provider.",
|
||||
"HEADERNAME": "Header Name",
|
||||
"JWTENDPOINT": "JWT Endpoint",
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint"
|
||||
"JWTKEYSENDPOINT": "JWT Keys Endpoint",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Salvato con successo.",
|
||||
|
||||
@@ -2366,7 +2366,8 @@
|
||||
"DESCRIPTION": "JWT Identity Providerの情報を入力する。",
|
||||
"HEADERNAME": "ヘッダー名",
|
||||
"JWTENDPOINT": "JWTエンドポイント",
|
||||
"JWTKEYSENDPOINT": "JWTキーエンドポイント"
|
||||
"JWTKEYSENDPOINT": "JWTキーエンドポイント",
|
||||
"AUDIENCE": "オーディエンス"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "チームID",
|
||||
|
||||
@@ -2366,7 +2366,8 @@
|
||||
"DESCRIPTION": "JWT ID 제공자에 필요한 데이터를 입력하세요.",
|
||||
"HEADERNAME": "헤더 이름",
|
||||
"JWTENDPOINT": "JWT 엔드포인트",
|
||||
"JWTKEYSENDPOINT": "JWT 키 엔드포인트"
|
||||
"JWTKEYSENDPOINT": "JWT 키 엔드포인트",
|
||||
"AUDIENCE": "청중"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "팀 ID",
|
||||
|
||||
@@ -2359,7 +2359,8 @@
|
||||
"DESCRIPTION": "Внесете ги податоците за JWT IDP.",
|
||||
"HEADERNAME": "Име на хедер",
|
||||
"JWTENDPOINT": "JWT Крајна точка",
|
||||
"JWTKEYSENDPOINT": "JWT Крајна точка за клучеви"
|
||||
"JWTKEYSENDPOINT": "JWT Крајна точка за клучеви",
|
||||
"AUDIENCE": "Аудиториум"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Успешно зачувано.",
|
||||
|
||||
@@ -2366,7 +2366,8 @@
|
||||
"DESCRIPTION": "Voer de gegevens in voor JWT Identity Provider.",
|
||||
"HEADERNAME": "Header Naam",
|
||||
"JWTENDPOINT": "JWT Eindpunt",
|
||||
"JWTKEYSENDPOINT": "JWT Sleutels Eindpunt"
|
||||
"JWTKEYSENDPOINT": "JWT Sleutels Eindpunt",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Team ID",
|
||||
|
||||
@@ -2362,7 +2362,8 @@
|
||||
"DESCRIPTION": "Wprowadź dane dla dostawcy tożsamości JWT.",
|
||||
"HEADERNAME": "Nazwa nagłówka",
|
||||
"JWTENDPOINT": "Punkt końcowy JWT",
|
||||
"JWTKEYSENDPOINT": "Punkt końcowy kluczy JWT"
|
||||
"JWTKEYSENDPOINT": "Punkt końcowy kluczy JWT",
|
||||
"AUDIENCE": "Odbiorca"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Zapisano pomyślnie.",
|
||||
|
||||
@@ -2358,7 +2358,8 @@
|
||||
"DESCRIPTION": "Insira os dados para o Provedor de Identidade JWT.",
|
||||
"HEADERNAME": "Nome do Cabeçalho",
|
||||
"JWTENDPOINT": "Endpoint JWT",
|
||||
"JWTKEYSENDPOINT": "Endpoint de Chaves JWT"
|
||||
"JWTKEYSENDPOINT": "Endpoint de Chaves JWT",
|
||||
"AUDIENCE": "Audiência"
|
||||
},
|
||||
"TOAST": {
|
||||
"SAVED": "Salvo com sucesso.",
|
||||
|
||||
@@ -2364,7 +2364,8 @@
|
||||
"DESCRIPTION": "Introduceți datele pentru furnizorul de identitate JWT.",
|
||||
"HEADERNAME": "Nume antet",
|
||||
"JWTENDPOINT": "Punct final JWT",
|
||||
"JWTKEYSENDPOINT": "Punct final chei JWT"
|
||||
"JWTKEYSENDPOINT": "Punct final chei JWT",
|
||||
"AUDIENCE": "Audiență"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "ID echipă",
|
||||
|
||||
@@ -2469,7 +2469,8 @@
|
||||
"DESCRIPTION": "Введите данные JWT для поставщика идентификационных данных .",
|
||||
"HEADERNAME": "Название заголовка",
|
||||
"JWTENDPOINT": "Конечная точка JWT",
|
||||
"JWTKEYSENDPOINT": "Конечная точка ключей JWT"
|
||||
"JWTKEYSENDPOINT": "Конечная точка ключей JWT",
|
||||
"AUDIENCE": "Аудитория"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Идентификатор команды",
|
||||
|
||||
@@ -2370,7 +2370,8 @@
|
||||
"DESCRIPTION": "Ange data för JWT-identitetsleverantören.",
|
||||
"HEADERNAME": "Header-namn",
|
||||
"JWTENDPOINT": "JWT-slutpunkt",
|
||||
"JWTKEYSENDPOINT": "JWT-nycklar slutpunkt"
|
||||
"JWTKEYSENDPOINT": "JWT-nycklar slutpunkt",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Team-ID",
|
||||
|
||||
@@ -2369,7 +2369,8 @@
|
||||
"DESCRIPTION": "JWT Kimlik Sağlayıcısı için verileri girin.",
|
||||
"HEADERNAME": "Başlık Adı",
|
||||
"JWTENDPOINT": "JWT Uç Noktası",
|
||||
"JWTKEYSENDPOINT": "JWT Anahtarları Uç Noktası"
|
||||
"JWTKEYSENDPOINT": "JWT Anahtarları Uç Noktası",
|
||||
"AUDIENCE": "Audience"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Takım ID",
|
||||
|
||||
@@ -2370,7 +2370,8 @@
|
||||
"DESCRIPTION": "Введіть дані для JWT постачальника ідентичності.",
|
||||
"HEADERNAME": "Назва заголовка",
|
||||
"JWTENDPOINT": "JWT кінцева точка",
|
||||
"JWTKEYSENDPOINT": "JWT кінцева точка ключів"
|
||||
"JWTKEYSENDPOINT": "JWT кінцева точка ключів",
|
||||
"AUDIENCE": "Аудиторія"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "ID команди",
|
||||
|
||||
@@ -2374,7 +2374,8 @@
|
||||
"DESCRIPTION": "输入 JWT 身份提供者的数据。",
|
||||
"HEADERNAME": "请求头名称",
|
||||
"JWTENDPOINT": "JWT 端点",
|
||||
"JWTKEYSENDPOINT": "JWT Keys 端点"
|
||||
"JWTKEYSENDPOINT": "JWT Keys 端点",
|
||||
"AUDIENCE": "受众"
|
||||
},
|
||||
"APPLE": {
|
||||
"TEAMID": "Team ID",
|
||||
|
||||
@@ -265,22 +265,24 @@ func updateGenericOIDCProviderToCommand(req *admin_pb.UpdateGenericOIDCProviderR
|
||||
|
||||
func addJWTProviderToCommand(req *admin_pb.AddJWTProviderRequest) command.JWTProvider {
|
||||
return command.JWTProvider{
|
||||
Name: req.Name,
|
||||
Issuer: req.Issuer,
|
||||
JWTEndpoint: req.JwtEndpoint,
|
||||
KeyEndpoint: req.KeysEndpoint,
|
||||
HeaderName: req.HeaderName,
|
||||
Name: req.GetName(),
|
||||
Issuer: req.GetIssuer(),
|
||||
JWTEndpoint: req.GetJwtEndpoint(),
|
||||
KeyEndpoint: req.GetKeysEndpoint(),
|
||||
HeaderName: req.GetHeaderName(),
|
||||
Audience: req.GetAudience(),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateJWTProviderToCommand(req *admin_pb.UpdateJWTProviderRequest) command.JWTProvider {
|
||||
return command.JWTProvider{
|
||||
Name: req.Name,
|
||||
Issuer: req.Issuer,
|
||||
JWTEndpoint: req.JwtEndpoint,
|
||||
KeyEndpoint: req.KeysEndpoint,
|
||||
HeaderName: req.HeaderName,
|
||||
Name: req.GetName(),
|
||||
Issuer: req.GetIssuer(),
|
||||
JWTEndpoint: req.GetJwtEndpoint(),
|
||||
KeyEndpoint: req.GetKeysEndpoint(),
|
||||
HeaderName: req.GetHeaderName(),
|
||||
Audience: req.GetAudience(),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,6 +529,7 @@ func jwtConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.JWTIDP
|
||||
Issuer: template.Issuer,
|
||||
KeysEndpoint: template.KeysEndpoint,
|
||||
HeaderName: template.HeaderName,
|
||||
Audience: template.Audience,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ func jwtConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.JWTIDPTemplate)
|
||||
Issuer: template.Issuer,
|
||||
KeysEndpoint: template.KeysEndpoint,
|
||||
HeaderName: template.HeaderName,
|
||||
Audience: template.Audience,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,22 +258,24 @@ func updateGenericOIDCProviderToCommand(req *mgmt_pb.UpdateGenericOIDCProviderRe
|
||||
|
||||
func addJWTProviderToCommand(req *mgmt_pb.AddJWTProviderRequest) command.JWTProvider {
|
||||
return command.JWTProvider{
|
||||
Name: req.Name,
|
||||
Issuer: req.Issuer,
|
||||
JWTEndpoint: req.JwtEndpoint,
|
||||
KeyEndpoint: req.KeysEndpoint,
|
||||
HeaderName: req.HeaderName,
|
||||
Name: req.GetName(),
|
||||
Issuer: req.GetIssuer(),
|
||||
JWTEndpoint: req.GetJwtEndpoint(),
|
||||
KeyEndpoint: req.GetKeysEndpoint(),
|
||||
HeaderName: req.GetHeaderName(),
|
||||
Audience: req.GetAudience(),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateJWTProviderToCommand(req *mgmt_pb.UpdateJWTProviderRequest) command.JWTProvider {
|
||||
return command.JWTProvider{
|
||||
Name: req.Name,
|
||||
Issuer: req.Issuer,
|
||||
JWTEndpoint: req.JwtEndpoint,
|
||||
KeyEndpoint: req.KeysEndpoint,
|
||||
HeaderName: req.HeaderName,
|
||||
Name: req.GetName(),
|
||||
Issuer: req.GetIssuer(),
|
||||
JWTEndpoint: req.GetJwtEndpoint(),
|
||||
KeyEndpoint: req.GetKeysEndpoint(),
|
||||
HeaderName: req.GetHeaderName(),
|
||||
Audience: req.GetAudience(),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,6 +1090,7 @@ func (l *Login) jwtProvider(identityProvider *query.IDPTemplate) (*jwt.Provider,
|
||||
identityProvider.JWTIDPTemplate.Endpoint,
|
||||
identityProvider.JWTIDPTemplate.KeysEndpoint,
|
||||
identityProvider.JWTIDPTemplate.HeaderName,
|
||||
identityProvider.JWTIDPTemplate.Audience,
|
||||
l.idpConfigAlg,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ type JWTProvider struct {
|
||||
JWTEndpoint string
|
||||
KeyEndpoint string
|
||||
HeaderName string
|
||||
Audience string
|
||||
IDPOptions idp.Options
|
||||
}
|
||||
|
||||
|
||||
@@ -430,6 +430,7 @@ type JWTIDPWriteModel struct {
|
||||
JWTEndpoint string
|
||||
KeysEndpoint string
|
||||
HeaderName string
|
||||
Audience string
|
||||
idp.Options
|
||||
|
||||
State domain.IDPState
|
||||
@@ -465,6 +466,7 @@ func (wm *JWTIDPWriteModel) reduceAddedEvent(e *idp.JWTIDPAddedEvent) {
|
||||
wm.JWTEndpoint = e.JWTEndpoint
|
||||
wm.KeysEndpoint = e.KeysEndpoint
|
||||
wm.HeaderName = e.HeaderName
|
||||
wm.Audience = e.Audience
|
||||
wm.Options = e.Options
|
||||
wm.State = domain.IDPStateActive
|
||||
}
|
||||
@@ -485,6 +487,9 @@ func (wm *JWTIDPWriteModel) reduceChangedEvent(e *idp.JWTIDPChangedEvent) {
|
||||
if e.HeaderName != nil {
|
||||
wm.HeaderName = *e.HeaderName
|
||||
}
|
||||
if e.Audience != nil {
|
||||
wm.Audience = *e.Audience
|
||||
}
|
||||
wm.Options.ReduceChanges(e.OptionChanges)
|
||||
}
|
||||
|
||||
@@ -493,7 +498,8 @@ func (wm *JWTIDPWriteModel) NewChanges(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options idp.Options,
|
||||
) ([]idp.JWTIDPChanges, error) {
|
||||
changes := make([]idp.JWTIDPChanges, 0)
|
||||
@@ -512,6 +518,9 @@ func (wm *JWTIDPWriteModel) NewChanges(
|
||||
if wm.HeaderName != headerName {
|
||||
changes = append(changes, idp.ChangeJWTHeaderName(headerName))
|
||||
}
|
||||
if wm.Audience != audience {
|
||||
changes = append(changes, idp.ChangeJWTAudience(audience))
|
||||
}
|
||||
opts := wm.Options.Changes(options)
|
||||
if !opts.IsZero() {
|
||||
changes = append(changes, idp.ChangeJWTOptions(opts))
|
||||
@@ -583,6 +592,7 @@ func (wm *JWTIDPWriteModel) ToProvider(callbackURL string, idpAlg crypto.Encrypt
|
||||
wm.JWTEndpoint,
|
||||
wm.KeysEndpoint,
|
||||
wm.HeaderName,
|
||||
wm.Audience,
|
||||
idpAlg,
|
||||
opts...,
|
||||
)
|
||||
|
||||
@@ -940,6 +940,7 @@ func (c *Commands) prepareAddInstanceJWTProvider(a *instance.Aggregate, writeMod
|
||||
provider.JWTEndpoint,
|
||||
provider.KeyEndpoint,
|
||||
provider.HeaderName,
|
||||
provider.Audience,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
@@ -988,6 +989,7 @@ func (c *Commands) prepareUpdateInstanceJWTProvider(a *instance.Aggregate, write
|
||||
provider.JWTEndpoint,
|
||||
provider.KeyEndpoint,
|
||||
provider.HeaderName,
|
||||
provider.Audience,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil || event == nil {
|
||||
|
||||
@@ -274,7 +274,8 @@ func (wm *InstanceJWTIDPWriteModel) NewChangedEvent(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options idp.Options,
|
||||
) (*instance.JWTIDPChangedEvent, error) {
|
||||
|
||||
@@ -284,6 +285,7 @@ func (wm *InstanceJWTIDPWriteModel) NewChangedEvent(
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName,
|
||||
audience,
|
||||
options,
|
||||
)
|
||||
if err != nil || len(changes) == 0 {
|
||||
|
||||
@@ -911,6 +911,7 @@ func (c *Commands) prepareAddOrgJWTProvider(a *org.Aggregate, writeModel *OrgJWT
|
||||
provider.JWTEndpoint,
|
||||
provider.KeyEndpoint,
|
||||
provider.HeaderName,
|
||||
provider.Audience,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
@@ -959,6 +960,7 @@ func (c *Commands) prepareUpdateOrgJWTProvider(a *org.Aggregate, writeModel *Org
|
||||
provider.JWTEndpoint,
|
||||
provider.KeyEndpoint,
|
||||
provider.HeaderName,
|
||||
provider.Audience,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil || event == nil {
|
||||
|
||||
@@ -276,7 +276,8 @@ func (wm *OrgJWTIDPWriteModel) NewChangedEvent(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options idp.Options,
|
||||
) (*org.JWTIDPChangedEvent, error) {
|
||||
|
||||
@@ -286,6 +287,7 @@ func (wm *OrgJWTIDPWriteModel) NewChangedEvent(
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName,
|
||||
audience,
|
||||
options,
|
||||
)
|
||||
if err != nil || len(changes) == 0 {
|
||||
|
||||
@@ -28,6 +28,7 @@ type Provider struct {
|
||||
issuer string
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
audience string
|
||||
isLinkingAllowed bool
|
||||
isCreationAllowed bool
|
||||
isAutoCreation bool
|
||||
@@ -67,13 +68,14 @@ func WithAutoUpdate() ProviderOpts {
|
||||
}
|
||||
|
||||
// New creates a JWT provider
|
||||
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
|
||||
func New(name, issuer, jwtEndpoint, keysEndpoint, headerName, audience string, encryptionAlg crypto.EncryptionAlgorithm, options ...ProviderOpts) (*Provider, error) {
|
||||
provider := &Provider{
|
||||
name: name,
|
||||
issuer: issuer,
|
||||
jwtEndpoint: jwtEndpoint,
|
||||
keysEndpoint: keysEndpoint,
|
||||
headerName: headerName,
|
||||
audience: audience,
|
||||
encryptionAlg: encryptionAlg,
|
||||
}
|
||||
for _, option := range options {
|
||||
|
||||
@@ -20,6 +20,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
@@ -43,6 +44,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -64,6 +66,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -83,6 +86,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -108,6 +112,7 @@ func TestProvider_BeginAuth(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -135,6 +140,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
opts []ProviderOpts
|
||||
}
|
||||
@@ -159,6 +165,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -181,6 +188,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -211,6 +219,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
tt.fields.opts...,
|
||||
)
|
||||
|
||||
@@ -100,6 +100,11 @@ func (s *Session) validateToken(ctx context.Context, token string) (*oidc.IDToke
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
|
||||
}
|
||||
|
||||
if s.Provider.audience != "" {
|
||||
if err = oidc.CheckAudience(claims, s.Provider.audience); err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err)
|
||||
}
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint string
|
||||
keysEndpoint string
|
||||
headerName string
|
||||
audience string
|
||||
encryptionAlg func(t *testing.T) crypto.EncryptionAlgorithm
|
||||
httpMock func(issuer string)
|
||||
authURL string
|
||||
@@ -60,6 +61,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -83,6 +85,36 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
httpMock: func(issuer string) {
|
||||
gock.New(issuer).
|
||||
Get("/keys").
|
||||
Reply(200).
|
||||
JSON(keys(t))
|
||||
},
|
||||
authURL: "https://auth.com/jwt?authRequestID=testState",
|
||||
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
|
||||
Token: &oauth2.Token{},
|
||||
IDToken: "invalidToken",
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, ErrInvalidToken)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid token (audience)",
|
||||
fields: fields{
|
||||
issuer: "https://jwt.com",
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "audience",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -214,6 +246,69 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "clientID",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
httpMock: func(issuer string) {
|
||||
gock.New(issuer).
|
||||
Get("/keys").
|
||||
Reply(200).
|
||||
JSON(keys(t))
|
||||
},
|
||||
authURL: "https://auth.com/jwt?authRequestID=testState",
|
||||
tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
|
||||
Token: &oauth2.Token{},
|
||||
IDToken: idToken(t, "https://jwt.com", time.Now().Add(time.Hour), 0),
|
||||
IDTokenClaims: &oidc.IDTokenClaims{
|
||||
TokenClaims: oidc.TokenClaims{
|
||||
Subject: "sub",
|
||||
},
|
||||
UserInfoProfile: oidc.UserInfoProfile{
|
||||
Picture: "picture",
|
||||
Name: "firstname lastname",
|
||||
GivenName: "firstname",
|
||||
FamilyName: "lastname",
|
||||
Nickname: "nickname",
|
||||
PreferredUsername: "username",
|
||||
Profile: "profile",
|
||||
Locale: oidc.NewLocale(language.English),
|
||||
},
|
||||
UserInfoEmail: oidc.UserInfoEmail{
|
||||
Email: "email",
|
||||
EmailVerified: oidc.Bool(true),
|
||||
},
|
||||
UserInfoPhone: oidc.UserInfoPhone{
|
||||
PhoneNumber: "phone",
|
||||
PhoneNumberVerified: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
id: "sub",
|
||||
firstName: "firstname",
|
||||
lastName: "lastname",
|
||||
displayName: "firstname lastname",
|
||||
nickName: "nickname",
|
||||
preferredUsername: "username",
|
||||
email: "email",
|
||||
isEmailVerified: true,
|
||||
phone: "phone",
|
||||
isPhoneVerified: true,
|
||||
preferredLanguage: language.English,
|
||||
avatarURL: "picture",
|
||||
profile: "profile",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "successful fetch (no audience check)",
|
||||
fields: fields{
|
||||
issuer: "https://jwt.com",
|
||||
jwtEndpoint: "https://auth.com/jwt",
|
||||
keysEndpoint: "https://jwt.com/keys",
|
||||
headerName: "jwt-header",
|
||||
audience: "",
|
||||
encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm {
|
||||
return crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
},
|
||||
@@ -281,6 +376,7 @@ func TestSession_FetchUser(t *testing.T) {
|
||||
tt.fields.jwtEndpoint,
|
||||
tt.fields.keysEndpoint,
|
||||
tt.fields.headerName,
|
||||
tt.fields.audience,
|
||||
tt.fields.encryptionAlg(t),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -82,6 +82,7 @@ type JWTIDPTemplate struct {
|
||||
KeysEndpoint string
|
||||
HeaderName string
|
||||
Endpoint string
|
||||
Audience string
|
||||
}
|
||||
|
||||
type AzureADIDPTemplate struct {
|
||||
@@ -355,6 +356,10 @@ var (
|
||||
name: projection.JWTHeaderNameCol,
|
||||
table: jwtIdpTemplateTable,
|
||||
}
|
||||
JWTAudienceCol = Column{
|
||||
name: projection.JWTAudienceCol,
|
||||
table: jwtIdpTemplateTable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -913,6 +918,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
JWTEndpointCol.identifier(),
|
||||
JWTKeysEndpointCol.identifier(),
|
||||
JWTHeaderNameCol.identifier(),
|
||||
JWTAudienceCol.identifier(),
|
||||
// azure
|
||||
AzureADIDCol.identifier(),
|
||||
AzureADClientIDCol.identifier(),
|
||||
@@ -1034,6 +1040,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
jwtEndpoint := sql.NullString{}
|
||||
jwtKeysEndpoint := sql.NullString{}
|
||||
jwtHeaderName := sql.NullString{}
|
||||
jwtAudience := sql.NullString{}
|
||||
|
||||
azureadID := sql.NullString{}
|
||||
azureadClientID := sql.NullString{}
|
||||
@@ -1153,6 +1160,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
&jwtEndpoint,
|
||||
&jwtKeysEndpoint,
|
||||
&jwtHeaderName,
|
||||
&jwtAudience,
|
||||
// azure
|
||||
&azureadID,
|
||||
&azureadClientID,
|
||||
@@ -1273,6 +1281,7 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
KeysEndpoint: jwtKeysEndpoint.String,
|
||||
HeaderName: jwtHeaderName.String,
|
||||
Endpoint: jwtEndpoint.String,
|
||||
Audience: jwtAudience.String,
|
||||
}
|
||||
}
|
||||
if azureadID.Valid {
|
||||
@@ -1429,6 +1438,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
JWTEndpointCol.identifier(),
|
||||
JWTKeysEndpointCol.identifier(),
|
||||
JWTHeaderNameCol.identifier(),
|
||||
JWTAudienceCol.identifier(),
|
||||
// azure
|
||||
AzureADIDCol.identifier(),
|
||||
AzureADClientIDCol.identifier(),
|
||||
@@ -1555,6 +1565,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
jwtEndpoint := sql.NullString{}
|
||||
jwtKeysEndpoint := sql.NullString{}
|
||||
jwtHeaderName := sql.NullString{}
|
||||
jwtAudience := sql.NullString{}
|
||||
|
||||
azureadID := sql.NullString{}
|
||||
azureadClientID := sql.NullString{}
|
||||
@@ -1674,6 +1685,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
&jwtEndpoint,
|
||||
&jwtKeysEndpoint,
|
||||
&jwtHeaderName,
|
||||
&jwtAudience,
|
||||
// azure
|
||||
&azureadID,
|
||||
&azureadClientID,
|
||||
@@ -1793,6 +1805,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
KeysEndpoint: jwtKeysEndpoint.String,
|
||||
HeaderName: jwtHeaderName.String,
|
||||
Endpoint: jwtEndpoint.String,
|
||||
Audience: jwtAudience.String,
|
||||
}
|
||||
}
|
||||
if azureadID.Valid {
|
||||
|
||||
@@ -54,6 +54,7 @@ var (
|
||||
` projections.idp_templates6_jwt.jwt_endpoint,` +
|
||||
` projections.idp_templates6_jwt.keys_endpoint,` +
|
||||
` projections.idp_templates6_jwt.header_name,` +
|
||||
` projections.idp_templates6_jwt.audience,` +
|
||||
// azure
|
||||
` projections.idp_templates6_azure.idp_id,` +
|
||||
` projections.idp_templates6_azure.client_id,` +
|
||||
@@ -185,6 +186,7 @@ var (
|
||||
"jwt_endpoint",
|
||||
"keys_endpoint",
|
||||
"header_name",
|
||||
"audience",
|
||||
// azure
|
||||
"idp_id",
|
||||
"client_id",
|
||||
@@ -303,6 +305,7 @@ var (
|
||||
` projections.idp_templates6_jwt.jwt_endpoint,` +
|
||||
` projections.idp_templates6_jwt.keys_endpoint,` +
|
||||
` projections.idp_templates6_jwt.header_name,` +
|
||||
` projections.idp_templates6_jwt.audience,` +
|
||||
// azure
|
||||
` projections.idp_templates6_azure.idp_id,` +
|
||||
` projections.idp_templates6_azure.client_id,` +
|
||||
@@ -435,6 +438,7 @@ var (
|
||||
"jwt_endpoint",
|
||||
"keys_endpoint",
|
||||
"header_name",
|
||||
"audience",
|
||||
// azure
|
||||
"idp_id",
|
||||
"client_id",
|
||||
@@ -593,6 +597,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -749,6 +754,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -903,6 +909,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
"jwt",
|
||||
"keys",
|
||||
"header",
|
||||
"audience",
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1006,6 +1013,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Endpoint: "jwt",
|
||||
KeysEndpoint: "keys",
|
||||
HeaderName: "header",
|
||||
Audience: "audience",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1055,6 +1063,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1206,6 +1215,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1357,6 +1367,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1509,6 +1520,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1660,6 +1672,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1817,6 +1830,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -1989,6 +2003,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2142,6 +2157,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2323,6 +2339,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2504,6 +2521,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2658,6 +2676,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2777,6 +2796,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -2896,6 +2916,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -3015,6 +3036,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -3134,6 +3156,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -3253,6 +3276,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
"jwt",
|
||||
"keys",
|
||||
"header",
|
||||
"audience",
|
||||
// azure
|
||||
nil,
|
||||
nil,
|
||||
@@ -3508,6 +3532,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
Endpoint: "jwt",
|
||||
KeysEndpoint: "keys",
|
||||
HeaderName: "header",
|
||||
Audience: "audience",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -221,5 +221,9 @@ func (p *relationalTablesProjection) reduceJWTIDPChangedColumns(payload *domain.
|
||||
payloadChanged = true
|
||||
payload.Issuer = *idpEvent.Issuer
|
||||
}
|
||||
if idpEvent.Audience != nil && *idpEvent.Audience != payload.Audience {
|
||||
payloadChanged = true
|
||||
payload.Audience = *idpEvent.Audience
|
||||
}
|
||||
return payloadChanged
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ const (
|
||||
JWTEndpointCol = "jwt_endpoint"
|
||||
JWTKeysEndpointCol = "keys_endpoint"
|
||||
JWTHeaderNameCol = "header_name"
|
||||
JWTAudienceCol = "audience"
|
||||
|
||||
AzureADIDCol = "idp_id"
|
||||
AzureADInstanceIDCol = "instance_id"
|
||||
@@ -258,6 +259,7 @@ func (*idpTemplateProjection) Init() *old_handler.Check {
|
||||
handler.NewColumn(JWTEndpointCol, handler.ColumnTypeText),
|
||||
handler.NewColumn(JWTKeysEndpointCol, handler.ColumnTypeText),
|
||||
handler.NewColumn(JWTHeaderNameCol, handler.ColumnTypeText, handler.Nullable()),
|
||||
handler.NewColumn(JWTAudienceCol, handler.ColumnTypeText, handler.Nullable()),
|
||||
},
|
||||
handler.NewPrimaryKey(JWTInstanceIDCol, JWTIDCol),
|
||||
IDPTemplateJWTSuffix,
|
||||
@@ -1046,6 +1048,7 @@ func (p *idpTemplateProjection) reduceJWTIDPAdded(event eventstore.Event) (*hand
|
||||
handler.NewCol(JWTEndpointCol, idpEvent.JWTEndpoint),
|
||||
handler.NewCol(JWTKeysEndpointCol, idpEvent.KeysEndpoint),
|
||||
handler.NewCol(JWTHeaderNameCol, idpEvent.HeaderName),
|
||||
handler.NewCol(JWTAudienceCol, idpEvent.Audience),
|
||||
},
|
||||
handler.WithTableSuffix(IDPTemplateJWTSuffix),
|
||||
),
|
||||
@@ -2340,6 +2343,9 @@ func reduceJWTIDPChangedColumns(idpEvent idp.JWTIDPChangedEvent) []handler.Colum
|
||||
if idpEvent.Issuer != nil {
|
||||
jwtCols = append(jwtCols, handler.NewCol(JWTIssuerCol, *idpEvent.Issuer))
|
||||
}
|
||||
if idpEvent.Audience != nil {
|
||||
jwtCols = append(jwtCols, handler.NewCol(JWTAudienceCol, *idpEvent.Audience))
|
||||
}
|
||||
return jwtCols
|
||||
}
|
||||
|
||||
|
||||
@@ -4280,7 +4280,8 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true,
|
||||
"autoLinkingOption": 1
|
||||
"autoLinkingOption": 1,
|
||||
"audience": "audience"
|
||||
}`),
|
||||
), instance.JWTIDPAddedEventMapper),
|
||||
},
|
||||
@@ -4311,7 +4312,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name, audience) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
@@ -4319,6 +4320,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
"jwt",
|
||||
"keys",
|
||||
"header",
|
||||
"audience",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4342,7 +4344,8 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true,
|
||||
"autoLinkingOption": 1
|
||||
"autoLinkingOption": 1,
|
||||
"audience": "audience"
|
||||
}`),
|
||||
), org.JWTIDPAddedEventMapper),
|
||||
},
|
||||
@@ -4373,7 +4376,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name) VALUES ($1, $2, $3, $4, $5, $6)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates6_jwt (idp_id, instance_id, issuer, jwt_endpoint, keys_endpoint, header_name, audience) VALUES ($1, $2, $3, $4, $5, $6, $7)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
@@ -4381,6 +4384,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
"jwt",
|
||||
"keys",
|
||||
"header",
|
||||
"audience",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4442,6 +4446,7 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
"jwtEndpoint": "jwt",
|
||||
"keysEndpoint": "keys",
|
||||
"headerName": "header",
|
||||
"audience": "audience",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
@@ -4471,12 +4476,13 @@ func TestIDPTemplateProjection_reducesJWT(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates6_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer) = ($1, $2, $3, $4) WHERE (idp_id = $5) AND (instance_id = $6)",
|
||||
expectedStmt: "UPDATE projections.idp_templates6_jwt SET (jwt_endpoint, keys_endpoint, header_name, issuer, audience) = ($1, $2, $3, $4, $5) WHERE (idp_id = $6) AND (instance_id = $7)",
|
||||
expectedArgs: []interface{}{
|
||||
"jwt",
|
||||
"keys",
|
||||
"header",
|
||||
"issuer",
|
||||
"audience",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ type JWTIDPAddedEvent struct {
|
||||
JWTEndpoint string `json:"jwtEndpoint,omitempty"`
|
||||
KeysEndpoint string `json:"keysEndpoint,omitempty"`
|
||||
HeaderName string `json:"headerName,omitempty"`
|
||||
Audience string `json:"audience,omitempty"`
|
||||
Options
|
||||
}
|
||||
|
||||
@@ -24,7 +25,8 @@ func NewJWTIDPAddedEvent(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options Options,
|
||||
) *JWTIDPAddedEvent {
|
||||
return &JWTIDPAddedEvent{
|
||||
@@ -35,6 +37,7 @@ func NewJWTIDPAddedEvent(
|
||||
JWTEndpoint: jwtEndpoint,
|
||||
KeysEndpoint: keysEndpoint,
|
||||
HeaderName: headerName,
|
||||
Audience: audience,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
@@ -69,6 +72,7 @@ type JWTIDPChangedEvent struct {
|
||||
JWTEndpoint *string `json:"jwtEndpoint,omitempty"`
|
||||
KeysEndpoint *string `json:"keysEndpoint,omitempty"`
|
||||
HeaderName *string `json:"headerName,omitempty"`
|
||||
Audience *string `json:"audience,omitempty"`
|
||||
OptionChanges
|
||||
}
|
||||
|
||||
@@ -122,6 +126,12 @@ func ChangeJWTHeaderName(headerName string) func(*JWTIDPChangedEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeJWTAudience(audience string) func(*JWTIDPChangedEvent) {
|
||||
return func(e *JWTIDPChangedEvent) {
|
||||
e.Audience = &audience
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeJWTOptions(options OptionChanges) func(*JWTIDPChangedEvent) {
|
||||
return func(e *JWTIDPChangedEvent) {
|
||||
e.OptionChanges = options
|
||||
|
||||
@@ -304,7 +304,8 @@ func NewJWTIDPAddedEvent(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options idp.Options,
|
||||
) *JWTIDPAddedEvent {
|
||||
|
||||
@@ -321,6 +322,7 @@ func NewJWTIDPAddedEvent(
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName,
|
||||
audience,
|
||||
options,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -304,7 +304,8 @@ func NewJWTIDPAddedEvent(
|
||||
issuer,
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName string,
|
||||
headerName,
|
||||
audience string,
|
||||
options idp.Options,
|
||||
) *JWTIDPAddedEvent {
|
||||
|
||||
@@ -321,6 +322,7 @@ func NewJWTIDPAddedEvent(
|
||||
jwtEndpoint,
|
||||
keysEndpoint,
|
||||
headerName,
|
||||
audience,
|
||||
options,
|
||||
),
|
||||
}
|
||||
|
||||
@@ -6542,6 +6542,13 @@ message AddJWTProviderRequest {
|
||||
string keys_endpoint = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string header_name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.Options provider_options = 6;
|
||||
string audience = 7 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
description: "the expected audience in the JWT, if not provided the audience is not validated";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message AddJWTProviderResponse {
|
||||
@@ -6562,6 +6569,13 @@ message UpdateJWTProviderRequest {
|
||||
string keys_endpoint = 5 [(validate.rules).string = {max_len: 200}];
|
||||
string header_name = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.Options provider_options = 7;
|
||||
string audience = 8 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
description: "the expected audience in the JWT, if not provided the audience is not validated";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message UpdateJWTProviderResponse {
|
||||
|
||||
@@ -195,6 +195,13 @@ message JWTConfig {
|
||||
description: "the name of the header where the JWT is sent in, default is authorization";
|
||||
}
|
||||
];
|
||||
string audience = 5 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
description: "the expected audience in the JWT, if not provided the audience is not validated";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message IDPIDQuery {
|
||||
|
||||
@@ -133,6 +133,13 @@ message JWTConfig {
|
||||
"\"x-auth-token\"";
|
||||
}
|
||||
];
|
||||
// The audience is the expected audience in the JWT, if not configured, the audience is not validated.
|
||||
string audience = 5 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message OAuthConfig {
|
||||
|
||||
@@ -13291,6 +13291,13 @@ message AddJWTProviderRequest {
|
||||
string keys_endpoint = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string header_name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.Options provider_options = 6;
|
||||
string audience = 7 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
description: "the expected audience in the JWT, if not provided the audience is not validated";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message AddJWTProviderResponse {
|
||||
@@ -13311,6 +13318,13 @@ message UpdateJWTProviderRequest {
|
||||
string keys_endpoint = 5 [(validate.rules).string = {max_len: 200}];
|
||||
string header_name = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.Options provider_options = 7;
|
||||
string audience = 8 [
|
||||
(validate.rules).string = {max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"my-audience\"";
|
||||
description: "the expected audience in the JWT, if not provided the audience is not validated";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message UpdateJWTProviderResponse {
|
||||
|
||||
Reference in New Issue
Block a user