feat: extend start/retrieve idp intent for Zitadel provider (#12424)

# Which Problems Are Solved

This PR extends `StartIdentityProviderIntent` and
`RetrieveIdentityProviderIntent` for the new Zitadel provider.

# How the Problems Are Solved
- Added `domain.IDPTypeZitadel` cases to both the instance and org
switches in `NewAllIDPWriteModel` to return Zitadel provider when
`GetProvider` is called
- Added Zitadel provider to RetrieveIdentityProviderIntent's provider
type-switch
- Added new `zitadel.go` provider, an OIDC wrapper with forced PKCE
- Added unit/integration tests

# Additional Changes


# Additional Context
- Closes  https://github.com/zitadel/zitadel/issues/12050

---------

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
This commit is contained in:
gayathri
2026-07-17 13:24:18 +02:00
committed by GitHub
co-authored by Copilot Autofix powered by AI
parent 53d7920349
commit b91221143b
8 changed files with 755 additions and 0 deletions
+69
View File
@@ -17,6 +17,7 @@ import (
"github.com/zitadel/zitadel/internal/domain"
providers "github.com/zitadel/zitadel/internal/idp"
"github.com/zitadel/zitadel/internal/idp/providers/oauth"
"github.com/zitadel/zitadel/internal/idp/providers/zitadel"
"github.com/zitadel/zitadel/internal/zerrors"
)
@@ -167,6 +168,19 @@ func TestCommands_AllIDPWriteModel(t *testing.T) {
err: nil,
},
},
{
name: "writemodel instance zitadel",
args: args{
resourceOwner: "owner",
instanceBool: true,
id: "id",
idpType: domain.IDPTypeZitadel,
},
res: res{
writeModelType: &InstanceZitadelIDPWriteModel{},
err: nil,
},
},
{
name: "writemodel instance saml",
args: args{
@@ -322,6 +336,19 @@ func TestCommands_AllIDPWriteModel(t *testing.T) {
err: nil,
},
},
{
name: "writemodel org zitadel",
args: args{
resourceOwner: "owner",
instanceBool: false,
id: "id",
idpType: domain.IDPTypeZitadel,
},
res: res{
writeModelType: &OrgZitadelIDPWriteModel{},
err: nil,
},
},
{
name: "writemodel org saml",
args: args{
@@ -424,6 +451,48 @@ func TestOIDCIDPWriteModel_ToProvider_WithPKCE(t *testing.T) {
assertProviderUsesPKCE(t, provider)
}
func TestZitadelIDPWriteModel_ToProvider(t *testing.T) {
var (
issuer string
discoveryRequested atomic.Bool
)
handler := func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != oidc_pkg.DiscoveryEndpoint {
http.NotFound(w, r)
return
}
discoveryRequested.Store(true)
w.Header().Set("Content-Type", "application/json")
// assert, not require: FailNow must not be called from the server's handler goroutine
assert.NoError(t, json.NewEncoder(w).Encode(&oidc_pkg.DiscoveryConfiguration{
Issuer: issuer,
AuthorizationEndpoint: issuer + "/authorize",
TokenEndpoint: issuer + "/token",
UserinfoEndpoint: issuer + "/userinfo",
}))
}
server := httptest.NewServer(http.HandlerFunc(handler))
t.Cleanup(server.Close)
issuer = server.URL
wm := &ZitadelIDPWriteModel{
Name: "ZITADEL",
Issuer: issuer,
ClientID: "clientID",
ClientSecret: &crypto.CryptoValue{Algorithm: "plain", Crypted: []byte("clientSecret"), KeyID: "keyID"},
Scopes: []string{"openid"},
}
provider, err := wm.ToProvider("https://zitadel.example.com/idps/callback", plainTextEncryption{}, http.DefaultClient)
require.NoError(t, err)
require.IsType(t, &zitadel.Provider{}, provider)
require.True(t, discoveryRequested.Load(), "expected OIDC discovery to be requested")
// the ZITADEL provider always enforces PKCE
assertProviderUsesPKCE(t, provider)
}
func assertProviderUsesPKCE(t *testing.T, provider providers.Provider) {
t.Helper()