mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-26 17:22:15 +00:00
feat: native app links for passkeys (#12580)
# Which Problems Are Solved - Native iOS/Android passkeys need OS trust files on the ZITADEL domain; without them, Associated Domains / App Links verification fails. - Operators could not configure iOS Team ID + Bundle ID or Android package name + SHA-256 fingerprints on OIDC apps. - `/.well-known/apple-app-site-association` and `/.well-known/assetlinks.json` were not served from application config. # How the Problems Are Solved - Add iOS/Android app-link fields on OIDC app create/update (Application API v2 + Management), with validation. - Persist and project those fields; query active app-link configs instance-wide. - Serve AASA (`webcredentials`) and Digital Asset Links (`get_login_creds`) from well-known paths, with configurable `Cache-Control` and fingerprint normalization at serve time. - Console UI to edit the fields, with links to the well-known endpoints. - Operator docs for configuration, endpoints, caching, and verification. # Additional Changes - Document on API fields that well-known responses may be HTTP-cached and platform verifiers may delay propagation. - Runtime config: `WellKnown.AppLinksCacheControlMaxAge` (default `5m`; `0` → `no-store`). # Additional Context - Closes #12497 - Implemented and reviewed as stack: - #12531 API contract - #12532 storage wiring - #12536 well-known endpoints - #12537 console - #12547 docs --------- Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -158,7 +158,10 @@ func TestCommandSide_AddInstanceDomain(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
|
||||
@@ -125,7 +125,10 @@ func oidcAppEvents(ctx context.Context, orgID, projectID, id, name, clientID str
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,7 +471,10 @@ func generatedDomainFilters(instanceID, orgID, projectID, appID, generatedDomain
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
expectFilter(
|
||||
func() eventstore.Event {
|
||||
|
||||
@@ -20,24 +20,28 @@ import (
|
||||
|
||||
type addOIDCApp struct {
|
||||
AddApp
|
||||
Version domain.OIDCVersion
|
||||
RedirectUris []string
|
||||
ResponseTypes []domain.OIDCResponseType
|
||||
GrantTypes []domain.OIDCGrantType
|
||||
ApplicationType domain.OIDCApplicationType
|
||||
AuthMethodType domain.OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
DevMode bool
|
||||
AccessTokenType domain.OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
AdditionalOrigins []string
|
||||
SkipSuccessPageForNativeApp bool
|
||||
BackChannelLogoutURI string
|
||||
LoginVersion domain.LoginVersion
|
||||
LoginBaseURI string
|
||||
Version domain.OIDCVersion
|
||||
RedirectUris []string
|
||||
ResponseTypes []domain.OIDCResponseType
|
||||
GrantTypes []domain.OIDCGrantType
|
||||
ApplicationType domain.OIDCApplicationType
|
||||
AuthMethodType domain.OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
DevMode bool
|
||||
AccessTokenType domain.OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
AdditionalOrigins []string
|
||||
SkipSuccessPageForNativeApp bool
|
||||
BackChannelLogoutURI string
|
||||
LoginVersion domain.LoginVersion
|
||||
LoginBaseURI string
|
||||
IOSTeamID string
|
||||
IOSBundleID string
|
||||
AndroidPackageName string
|
||||
AndroidSHA256CertFingerprints []string
|
||||
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
@@ -118,6 +122,10 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp) preparation.Validation {
|
||||
app.BackChannelLogoutURI,
|
||||
app.LoginVersion,
|
||||
app.LoginBaseURI,
|
||||
app.IOSTeamID,
|
||||
app.IOSBundleID,
|
||||
app.AndroidPackageName,
|
||||
app.AndroidSHA256CertFingerprints,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
@@ -251,6 +259,10 @@ func (c *Commands) pushOIDCApplication(ctx context.Context, addedApplication *OI
|
||||
backchannelLogoutURI,
|
||||
gu.Value(oidcApp.LoginVersion),
|
||||
strings.TrimSpace(gu.Value(oidcApp.LoginBaseURI)),
|
||||
strings.TrimSpace(gu.Value(oidcApp.IOSTeamID)),
|
||||
strings.TrimSpace(gu.Value(oidcApp.IOSBundleID)),
|
||||
strings.TrimSpace(gu.Value(oidcApp.AndroidPackageName)),
|
||||
trimStringSliceWhiteSpaces(oidcApp.AndroidSHA256CertFingerprints),
|
||||
))
|
||||
|
||||
events = append(events, extraEvents...)
|
||||
@@ -340,7 +352,7 @@ func (c *Commands) UpdateOIDCApplication(ctx context.Context, oidc *domain.OIDCA
|
||||
// UpdateDynamicOIDCClient). It reports whether anything actually changed.
|
||||
func (c *Commands) oidcApplicationChangeEvent(ctx context.Context, existingOIDC *OIDCApplicationWriteModel, oidc *domain.OIDCApp) (*project_repo.OIDCConfigChangedEvent, bool, error) {
|
||||
projectAgg := ProjectAggregateFromWriteModelWithCTX(ctx, &existingOIDC.WriteModel)
|
||||
var backChannelLogout, loginBaseURI *string
|
||||
var backChannelLogout, loginBaseURI, iosTeamID, iosBundleID, androidPackageName *string
|
||||
if oidc.BackChannelLogoutURI != nil {
|
||||
bcl, err := c.validateBackchannelLogoutURI(oidc)
|
||||
if err != nil {
|
||||
@@ -352,6 +364,15 @@ func (c *Commands) oidcApplicationChangeEvent(ctx context.Context, existingOIDC
|
||||
if oidc.LoginBaseURI != nil {
|
||||
loginBaseURI = gu.Ptr(strings.TrimSpace(*oidc.LoginBaseURI))
|
||||
}
|
||||
if oidc.IOSTeamID != nil {
|
||||
iosTeamID = gu.Ptr(strings.TrimSpace(*oidc.IOSTeamID))
|
||||
}
|
||||
if oidc.IOSBundleID != nil {
|
||||
iosBundleID = gu.Ptr(strings.TrimSpace(*oidc.IOSBundleID))
|
||||
}
|
||||
if oidc.AndroidPackageName != nil {
|
||||
androidPackageName = gu.Ptr(strings.TrimSpace(*oidc.AndroidPackageName))
|
||||
}
|
||||
|
||||
return existingOIDC.NewChangedEvent(
|
||||
ctx,
|
||||
@@ -375,6 +396,10 @@ func (c *Commands) oidcApplicationChangeEvent(ctx context.Context, existingOIDC
|
||||
backChannelLogout,
|
||||
oidc.LoginVersion,
|
||||
loginBaseURI,
|
||||
iosTeamID,
|
||||
iosBundleID,
|
||||
androidPackageName,
|
||||
trimStringSliceWhiteSpaces(oidc.AndroidSHA256CertFingerprints),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,10 @@ func TestCommandSide_AddDynamicOIDCClient(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
// The registration access token (RFC 7592 §3) is persisted in the same
|
||||
// push as the application, so a registered client is never left
|
||||
// unmanageable.
|
||||
@@ -336,7 +339,10 @@ func TestCommandSide_AddDynamicOIDCClient(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
project.NewOIDCConfigRegistrationTokenChangedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
@@ -581,7 +587,11 @@ func TestCommandSide_UpdateDynamicOIDCClient(t *testing.T) {
|
||||
domain.OIDCApplicationTypeWeb, domain.OIDCAuthMethodTypeNone,
|
||||
[]string{}, false, domain.OIDCTokenTypeBearer,
|
||||
false, false, false, 0, []string{}, false, "",
|
||||
domain.LoginVersionUnspecified, "")),
|
||||
domain.LoginVersionUnspecified, "",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil)),
|
||||
}
|
||||
}
|
||||
sameMetadata := &domain.OIDCApp{
|
||||
|
||||
@@ -14,32 +14,36 @@ import (
|
||||
type OIDCApplicationWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
AppID string
|
||||
AppName string
|
||||
ClientID string
|
||||
HashedSecret string
|
||||
ClientSecretString string
|
||||
RedirectUris []string
|
||||
ResponseTypes []domain.OIDCResponseType
|
||||
GrantTypes []domain.OIDCGrantType
|
||||
ApplicationType domain.OIDCApplicationType
|
||||
AuthMethodType domain.OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
OIDCVersion domain.OIDCVersion
|
||||
Compliance *domain.Compliance
|
||||
DevMode bool
|
||||
AccessTokenType domain.OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
State domain.AppState
|
||||
AdditionalOrigins []string
|
||||
SkipNativeAppSuccessPage bool
|
||||
BackChannelLogoutURI string
|
||||
LoginVersion domain.LoginVersion
|
||||
LoginBaseURI string
|
||||
oidc bool
|
||||
AppID string
|
||||
AppName string
|
||||
ClientID string
|
||||
HashedSecret string
|
||||
ClientSecretString string
|
||||
RedirectUris []string
|
||||
ResponseTypes []domain.OIDCResponseType
|
||||
GrantTypes []domain.OIDCGrantType
|
||||
ApplicationType domain.OIDCApplicationType
|
||||
AuthMethodType domain.OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
OIDCVersion domain.OIDCVersion
|
||||
Compliance *domain.Compliance
|
||||
DevMode bool
|
||||
AccessTokenType domain.OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
State domain.AppState
|
||||
AdditionalOrigins []string
|
||||
SkipNativeAppSuccessPage bool
|
||||
BackChannelLogoutURI string
|
||||
LoginVersion domain.LoginVersion
|
||||
LoginBaseURI string
|
||||
IOSTeamID string
|
||||
IOSBundleID string
|
||||
AndroidPackageName string
|
||||
AndroidSHA256CertFingerprints []string
|
||||
oidc bool
|
||||
}
|
||||
|
||||
func NewOIDCApplicationWriteModelWithAppID(projectID, appID, resourceOwner string) *OIDCApplicationWriteModel {
|
||||
@@ -140,6 +144,10 @@ func (wm *OIDCApplicationWriteModel) Reduce() error {
|
||||
wm.BackChannelLogoutURI = ""
|
||||
wm.LoginVersion = domain.LoginVersionUnspecified
|
||||
wm.LoginBaseURI = ""
|
||||
wm.IOSTeamID = ""
|
||||
wm.IOSBundleID = ""
|
||||
wm.AndroidPackageName = ""
|
||||
wm.AndroidSHA256CertFingerprints = nil
|
||||
wm.oidc = false
|
||||
wm.AppName = e.Name
|
||||
wm.State = domain.AppStateActive
|
||||
@@ -189,6 +197,10 @@ func (wm *OIDCApplicationWriteModel) Reduce() error {
|
||||
wm.BackChannelLogoutURI = ""
|
||||
wm.LoginVersion = domain.LoginVersionUnspecified
|
||||
wm.LoginBaseURI = ""
|
||||
wm.IOSTeamID = ""
|
||||
wm.IOSBundleID = ""
|
||||
wm.AndroidPackageName = ""
|
||||
wm.AndroidSHA256CertFingerprints = nil
|
||||
wm.oidc = false
|
||||
wm.State = domain.AppStateRemoved
|
||||
}
|
||||
@@ -218,6 +230,10 @@ func (wm *OIDCApplicationWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAdd
|
||||
wm.BackChannelLogoutURI = e.BackChannelLogoutURI
|
||||
wm.LoginVersion = e.LoginVersion
|
||||
wm.LoginBaseURI = e.LoginBaseURI
|
||||
wm.IOSTeamID = e.IOSTeamID
|
||||
wm.IOSBundleID = e.IOSBundleID
|
||||
wm.AndroidPackageName = e.AndroidPackageName
|
||||
wm.AndroidSHA256CertFingerprints = e.AndroidSHA256CertFingerprints
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) appendChangeOIDCEvent(e *project.OIDCConfigChangedEvent) {
|
||||
@@ -275,6 +291,18 @@ func (wm *OIDCApplicationWriteModel) appendChangeOIDCEvent(e *project.OIDCConfig
|
||||
if e.LoginBaseURI != nil {
|
||||
wm.LoginBaseURI = *e.LoginBaseURI
|
||||
}
|
||||
if e.IOSTeamID != nil {
|
||||
wm.IOSTeamID = *e.IOSTeamID
|
||||
}
|
||||
if e.IOSBundleID != nil {
|
||||
wm.IOSBundleID = *e.IOSBundleID
|
||||
}
|
||||
if e.AndroidPackageName != nil {
|
||||
wm.AndroidPackageName = *e.AndroidPackageName
|
||||
}
|
||||
if e.AndroidSHA256CertFingerprints != nil {
|
||||
wm.AndroidSHA256CertFingerprints = *e.AndroidSHA256CertFingerprints
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
@@ -320,6 +348,10 @@ func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
||||
backChannelLogoutURI *string,
|
||||
loginVersion *domain.LoginVersion,
|
||||
loginBaseURI *string,
|
||||
iosTeamID *string,
|
||||
iosBundleID *string,
|
||||
androidPackageName *string,
|
||||
androidSHA256CertFingerprints []string,
|
||||
) (*project.OIDCConfigChangedEvent, bool, error) {
|
||||
changes := make([]project.OIDCConfigChanges, 0)
|
||||
var err error
|
||||
@@ -378,6 +410,18 @@ func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
||||
if loginBaseURI != nil && wm.LoginBaseURI != *loginBaseURI {
|
||||
changes = append(changes, project.ChangeOIDCLoginBaseURI(*loginBaseURI))
|
||||
}
|
||||
if iosTeamID != nil && wm.IOSTeamID != *iosTeamID {
|
||||
changes = append(changes, project.ChangeIOSTeamID(*iosTeamID))
|
||||
}
|
||||
if iosBundleID != nil && wm.IOSBundleID != *iosBundleID {
|
||||
changes = append(changes, project.ChangeIOSBundleID(*iosBundleID))
|
||||
}
|
||||
if androidPackageName != nil && wm.AndroidPackageName != *androidPackageName {
|
||||
changes = append(changes, project.ChangeAndroidPackageName(*androidPackageName))
|
||||
}
|
||||
if androidSHA256CertFingerprints != nil && !slices.Equal(wm.AndroidSHA256CertFingerprints, androidSHA256CertFingerprints) {
|
||||
changes = append(changes, project.ChangeAndroidSHA256CertFingerprints(androidSHA256CertFingerprints))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
)
|
||||
|
||||
func TestOIDCApplicationWriteModel_NewChangedEvent_AppLinks(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
agg := &project.NewAggregate("project-id", "org-id").Aggregate
|
||||
base := func() *OIDCApplicationWriteModel {
|
||||
return &OIDCApplicationWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: "project-id",
|
||||
ResourceOwner: "org-id",
|
||||
},
|
||||
AppID: "app-id",
|
||||
IOSTeamID: "OLDTEAM",
|
||||
IOSBundleID: "com.old.app",
|
||||
AndroidPackageName: "com.old.app",
|
||||
AndroidSHA256CertFingerprints: []string{"AA:AA"},
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("omit keeps existing", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
wm := base()
|
||||
event, hasChanged, err := wm.NewChangedEvent(
|
||||
context.Background(), agg, "app-id",
|
||||
nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, hasChanged)
|
||||
assert.Nil(t, event)
|
||||
})
|
||||
|
||||
t.Run("set changes fields", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
wm := base()
|
||||
event, hasChanged, err := wm.NewChangedEvent(
|
||||
context.Background(), agg, "app-id",
|
||||
nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
gu.Ptr("NEWTEAM"),
|
||||
gu.Ptr("com.new.app"),
|
||||
gu.Ptr("com.new.app"),
|
||||
[]string{"BB:BB"},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.True(t, hasChanged)
|
||||
require.NotNil(t, event)
|
||||
assert.Equal(t, gu.Ptr("NEWTEAM"), event.IOSTeamID)
|
||||
assert.Equal(t, gu.Ptr("com.new.app"), event.IOSBundleID)
|
||||
assert.Equal(t, gu.Ptr("com.new.app"), event.AndroidPackageName)
|
||||
assert.Equal(t, &[]string{"BB:BB"}, event.AndroidSHA256CertFingerprints)
|
||||
})
|
||||
|
||||
t.Run("clear with empty values", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
wm := base()
|
||||
event, hasChanged, err := wm.NewChangedEvent(
|
||||
context.Background(), agg, "app-id",
|
||||
nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
|
||||
gu.Ptr(""),
|
||||
gu.Ptr(""),
|
||||
gu.Ptr(""),
|
||||
[]string{},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
require.True(t, hasChanged)
|
||||
require.NotNil(t, event)
|
||||
assert.Equal(t, gu.Ptr(""), event.IOSTeamID)
|
||||
assert.Equal(t, gu.Ptr(""), event.IOSBundleID)
|
||||
assert.Equal(t, gu.Ptr(""), event.AndroidPackageName)
|
||||
assert.Equal(t, &[]string{}, event.AndroidSHA256CertFingerprints)
|
||||
})
|
||||
}
|
||||
@@ -176,7 +176,10 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -244,7 +247,10 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -312,7 +318,10 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -380,7 +389,10 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -534,7 +546,10 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion2,
|
||||
"https://login.test.ch",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
|
||||
@@ -643,7 +658,10 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion2,
|
||||
"https://login.test.ch",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "client1"),
|
||||
@@ -753,7 +771,10 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion2,
|
||||
"https://login.test.ch",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "app1", "client1"),
|
||||
@@ -1072,7 +1093,10 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion2,
|
||||
"https://login.test.ch",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
@@ -1147,7 +1171,10 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion2,
|
||||
"https://login.test.ch",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
@@ -1222,7 +1249,10 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
"https://test.ch/backchannel",
|
||||
domain.LoginVersion1,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
@@ -1316,7 +1346,10 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
@@ -1376,7 +1409,10 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
@@ -1531,7 +1567,10 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
|
||||
@@ -118,7 +118,10 @@ func TestCommandSide_ChangeApplicationSecret(t *testing.T) {
|
||||
"",
|
||||
domain.LoginVersionUnspecified,
|
||||
"",
|
||||
),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
nil),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
|
||||
@@ -29,32 +29,45 @@ func projectGrantWriteModelToProjectGrant(writeModel *ProjectGrantWriteModel) *d
|
||||
|
||||
func oidcWriteModelToOIDCConfig(writeModel *OIDCApplicationWriteModel) *domain.OIDCApp {
|
||||
return &domain.OIDCApp{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
AppID: writeModel.AppID,
|
||||
AppName: writeModel.AppName,
|
||||
State: writeModel.State,
|
||||
ClientID: writeModel.ClientID,
|
||||
RedirectUris: writeModel.RedirectUris,
|
||||
ResponseTypes: writeModel.ResponseTypes,
|
||||
GrantTypes: writeModel.GrantTypes,
|
||||
ApplicationType: gu.Ptr(writeModel.ApplicationType),
|
||||
AuthMethodType: gu.Ptr(writeModel.AuthMethodType),
|
||||
PostLogoutRedirectUris: writeModel.PostLogoutRedirectUris,
|
||||
OIDCVersion: gu.Ptr(writeModel.OIDCVersion),
|
||||
DevMode: gu.Ptr(writeModel.DevMode),
|
||||
AccessTokenType: gu.Ptr(writeModel.AccessTokenType),
|
||||
AccessTokenRoleAssertion: gu.Ptr(writeModel.AccessTokenRoleAssertion),
|
||||
IDTokenRoleAssertion: gu.Ptr(writeModel.IDTokenRoleAssertion),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(writeModel.IDTokenUserinfoAssertion),
|
||||
ClockSkew: gu.Ptr(writeModel.ClockSkew),
|
||||
AdditionalOrigins: writeModel.AdditionalOrigins,
|
||||
SkipNativeAppSuccessPage: gu.Ptr(writeModel.SkipNativeAppSuccessPage),
|
||||
BackChannelLogoutURI: gu.Ptr(writeModel.BackChannelLogoutURI),
|
||||
LoginVersion: gu.Ptr(writeModel.LoginVersion),
|
||||
LoginBaseURI: gu.Ptr(writeModel.LoginBaseURI),
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
AppID: writeModel.AppID,
|
||||
AppName: writeModel.AppName,
|
||||
State: writeModel.State,
|
||||
ClientID: writeModel.ClientID,
|
||||
RedirectUris: writeModel.RedirectUris,
|
||||
ResponseTypes: writeModel.ResponseTypes,
|
||||
GrantTypes: writeModel.GrantTypes,
|
||||
ApplicationType: gu.Ptr(writeModel.ApplicationType),
|
||||
AuthMethodType: gu.Ptr(writeModel.AuthMethodType),
|
||||
PostLogoutRedirectUris: writeModel.PostLogoutRedirectUris,
|
||||
OIDCVersion: gu.Ptr(writeModel.OIDCVersion),
|
||||
DevMode: gu.Ptr(writeModel.DevMode),
|
||||
AccessTokenType: gu.Ptr(writeModel.AccessTokenType),
|
||||
AccessTokenRoleAssertion: gu.Ptr(writeModel.AccessTokenRoleAssertion),
|
||||
IDTokenRoleAssertion: gu.Ptr(writeModel.IDTokenRoleAssertion),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(writeModel.IDTokenUserinfoAssertion),
|
||||
ClockSkew: gu.Ptr(writeModel.ClockSkew),
|
||||
AdditionalOrigins: writeModel.AdditionalOrigins,
|
||||
SkipNativeAppSuccessPage: gu.Ptr(writeModel.SkipNativeAppSuccessPage),
|
||||
BackChannelLogoutURI: gu.Ptr(writeModel.BackChannelLogoutURI),
|
||||
LoginVersion: gu.Ptr(writeModel.LoginVersion),
|
||||
LoginBaseURI: gu.Ptr(writeModel.LoginBaseURI),
|
||||
IOSTeamID: emptyStringPtr(writeModel.IOSTeamID),
|
||||
IOSBundleID: emptyStringPtr(writeModel.IOSBundleID),
|
||||
AndroidPackageName: emptyStringPtr(writeModel.AndroidPackageName),
|
||||
AndroidSHA256CertFingerprints: writeModel.AndroidSHA256CertFingerprints,
|
||||
}
|
||||
}
|
||||
|
||||
// emptyStringPtr returns nil for empty strings so unset app-link fields stay
|
||||
// distinguishable from explicitly set values in equality checks / APIs.
|
||||
func emptyStringPtr(s string) *string {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return gu.Ptr(s)
|
||||
}
|
||||
|
||||
func samlWriteModelToSAMLConfig(writeModel *SAMLApplicationWriteModel) *domain.SAMLApp {
|
||||
return &domain.SAMLApp{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
|
||||
Reference in New Issue
Block a user