feat: specify login UI version on instance and apps (#9071)

# Which Problems Are Solved

To be able to migrate or test the new login UI, admins might want to
(temporarily) switch individual apps.
At a later point admin might want to make sure all applications use the
new login UI.

# How the Problems Are Solved

- Added a feature flag `` on instance level to require all apps to use
the new login and provide an optional base url.
- if the flag is enabled, all (OIDC) applications will automatically use
the v2 login.
  - if disabled, applications can decide based on their configuration
- Added an option on OIDC apps to use the new login UI and an optional
base url.
- Removed the requirement to use `x-zitadel-login-client` to be
redirected to the login V2 and retrieve created authrequest and link
them to SSO sessions.
- Added a new "IAM_LOGIN_CLIENT" role to allow management of users,
sessions, grants and more without `x-zitadel-login-client`.

# Additional Changes

None

# Additional Context

closes https://github.com/zitadel/zitadel/issues/8702
This commit is contained in:
Livio Spring
2024-12-19 10:37:46 +01:00
committed by GitHub
parent b5e92a6144
commit 50d2b26a28
89 changed files with 1670 additions and 321 deletions

View File

@@ -176,6 +176,8 @@ func TestAddOIDCApp(t *testing.T) {
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
},
},
@@ -242,6 +244,8 @@ func TestAddOIDCApp(t *testing.T) {
nil,
false,
"",
domain.LoginVersionUnspecified,
"",
),
},
},
@@ -308,6 +312,8 @@ func TestAddOIDCApp(t *testing.T) {
nil,
false,
"",
domain.LoginVersionUnspecified,
"",
),
},
},
@@ -374,6 +380,8 @@ func TestAddOIDCApp(t *testing.T) {
nil,
false,
"",
domain.LoginVersionUnspecified,
"",
),
},
},
@@ -521,6 +529,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
[]string{"https://sub.test.ch"},
true,
"https://test.ch/backchannel",
domain.LoginVersion2,
"https://login.test.ch",
),
),
),
@@ -549,6 +559,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{" https://sub.test.ch "},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: " https://test.ch/backchannel ",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: " https://login.test.ch ",
},
resourceOwner: "org1",
},
@@ -578,6 +590,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
State: domain.AppStateActive,
Compliance: &domain.Compliance{},
},
@@ -622,6 +636,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
[]string{"https://sub.test.ch"},
true,
"https://test.ch/backchannel",
domain.LoginVersion2,
"https://login.test.ch",
),
),
),
@@ -650,6 +666,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
},
resourceOwner: "org1",
},
@@ -679,6 +697,8 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
State: domain.AppStateActive,
Compliance: &domain.Compliance{},
},
@@ -712,7 +732,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
eventstore func(*testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
@@ -732,9 +752,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "invalid app, invalid argument error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -753,9 +771,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "missing appid, invalid argument error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -777,9 +793,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "missing aggregateid, invalid argument error",
fields: fields{
eventstore: eventstoreExpect(
t,
),
eventstore: expectEventstore(),
},
args: args{
ctx: context.Background(),
@@ -801,8 +815,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "app not existing, not found error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(),
),
},
@@ -826,8 +839,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "no changes, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(),
@@ -858,6 +870,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
[]string{"https://sub.test.ch"},
true,
"https://test.ch/backchannel",
domain.LoginVersion2,
"https://login.test.ch",
),
),
),
@@ -887,6 +901,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
},
resourceOwner: "org1",
},
@@ -897,8 +913,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "no changes whitespaces are ignored, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(),
@@ -929,6 +944,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
[]string{"https://sub.test.ch"},
true,
"https://test.ch/backchannel",
domain.LoginVersion2,
"https://login.test.ch",
),
),
),
@@ -958,6 +975,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{" https://sub.test.ch "},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: " https://test.ch/backchannel ",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: " https://login.test.ch ",
},
resourceOwner: "org1",
},
@@ -968,8 +987,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
{
name: "change oidc app, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
project.NewApplicationAddedEvent(context.Background(),
@@ -1000,6 +1018,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
[]string{"https://sub.test.ch"},
true,
"https://test.ch/backchannel",
domain.LoginVersion1,
"",
),
),
),
@@ -1035,6 +1055,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
},
resourceOwner: "org1",
},
@@ -1063,6 +1085,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: true,
BackChannelLogoutURI: "https://test.ch/backchannel",
LoginVersion: domain.LoginVersion2,
LoginBaseURI: "https://login.test.ch",
Compliance: &domain.Compliance{},
State: domain.AppStateActive,
},
@@ -1072,7 +1096,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
eventstore: tt.fields.eventstore(t),
}
got, err := r.ChangeOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
if tt.res.err == nil {
@@ -1188,6 +1212,8 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
@@ -1232,6 +1258,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
AdditionalOrigins: []string{"https://sub.test.ch"},
SkipNativeAppSuccessPage: false,
BackChannelLogoutURI: "",
LoginVersion: domain.LoginVersionUnspecified,
State: domain.AppStateActive,
},
},
@@ -1270,6 +1297,8 @@ func newOIDCAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner
project.ChangeIDTokenRoleAssertion(false),
project.ChangeIDTokenUserinfoAssertion(false),
project.ChangeClockSkew(time.Second * 2),
project.ChangeLoginVersion(domain.LoginVersion2),
project.ChangeLoginBaseURI("https://login.test.ch"),
}
event, _ := project.NewOIDCConfigChangedEvent(ctx,
&project.NewAggregate(projectID, resourceOwner).Aggregate,
@@ -1347,6 +1376,8 @@ func TestCommands_VerifyOIDCClientSecret(t *testing.T) {
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
@@ -1383,6 +1414,8 @@ func TestCommands_VerifyOIDCClientSecret(t *testing.T) {
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),
@@ -1418,6 +1451,8 @@ func TestCommands_VerifyOIDCClientSecret(t *testing.T) {
[]string{"https://sub.test.ch"},
false,
"",
domain.LoginVersionUnspecified,
"",
),
),
),