mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-31 03:22:15 +00:00
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:
co-authored by
Copilot Autofix powered by AI
parent
53d7920349
commit
b91221143b
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
||||
saml2 "github.com/zitadel/zitadel/internal/idp/providers/saml"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/saml/requesttracker"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/zitadel"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
@@ -2279,6 +2280,8 @@ func NewAllIDPWriteModel(resourceOwner string, instanceBool bool, id string, idp
|
||||
writeModel.model = NewGoogleInstanceIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeApple:
|
||||
writeModel.model = NewAppleInstanceIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeZitadel:
|
||||
writeModel.model = NewInstanceZitadelIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeSAML:
|
||||
writeModel.samlModel = NewSAMLInstanceIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeUnspecified:
|
||||
@@ -2310,6 +2313,8 @@ func NewAllIDPWriteModel(resourceOwner string, instanceBool bool, id string, idp
|
||||
writeModel.model = NewGoogleOrgIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeApple:
|
||||
writeModel.model = NewAppleOrgIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeZitadel:
|
||||
writeModel.model = NewZitadelOrgIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeSAML:
|
||||
writeModel.samlModel = NewSAMLOrgIDPWriteModel(resourceOwner, id)
|
||||
case domain.IDPTypeUnspecified:
|
||||
@@ -2481,3 +2486,37 @@ func (wm *ZitadelIDPWriteModel) NewChanges(
|
||||
}
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
func (wm *ZitadelIDPWriteModel) ToProvider(callbackURL string, idpAlg crypto.EncryptionAlgorithm, httpClient *http.Client) (providers.Provider, error) {
|
||||
secret, err := crypto.DecryptString(wm.ClientSecret, idpAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := make([]oidc.ProviderOpts, 1, 7)
|
||||
opts[0] = oidc.WithSelectAccount()
|
||||
if wm.IsCreationAllowed {
|
||||
opts = append(opts, oidc.WithCreationAllowed())
|
||||
}
|
||||
if wm.IsLinkingAllowed {
|
||||
opts = append(opts, oidc.WithLinkingAllowed())
|
||||
}
|
||||
if wm.IsAutoCreation {
|
||||
opts = append(opts, oidc.WithAutoCreation())
|
||||
}
|
||||
if wm.IsAutoUpdate {
|
||||
opts = append(opts, oidc.WithAutoUpdate())
|
||||
}
|
||||
return zitadel.New(
|
||||
wm.Issuer,
|
||||
wm.ClientID,
|
||||
secret,
|
||||
callbackURL,
|
||||
wm.Scopes,
|
||||
httpClient,
|
||||
opts...,
|
||||
)
|
||||
}
|
||||
|
||||
func (wm *ZitadelIDPWriteModel) GetProviderOptions() idp.Options {
|
||||
return wm.Options
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user