fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! added first event

This commit is contained in:
Iraq Jaber
2025-08-07 09:19:23 +01:00
parent 1c603ef30c
commit 53811a1fd8
5 changed files with 1120 additions and 236 deletions

View File

@@ -6,6 +6,7 @@ import (
"github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
) )
//go:generate enumer -type IDPType -transform lower -trimprefix IDPType //go:generate enumer -type IDPType -transform lower -trimprefix IDPType
@@ -236,6 +237,35 @@ type IDPLDAP struct {
LDAP LDAP
} }
type Apple struct {
ClientID string `json:"clientId"`
TeamID string `json:"teamId"`
KeyID string `json:"keyId"`
PrivateKey *crypto.CryptoValue `json:"privateKey"`
Scopes []string `json:"scopes,omitempty"`
}
type IDPApple struct {
*IdentityProvider
Apple
}
type SAML struct {
Metadata []byte `json:"metadata,omitempty"`
Key *crypto.CryptoValue `json:"key,omitempty"`
Certificate []byte `json:"certificate,omitempty"`
Binding string `json:"binding,omitempty"`
WithSignedRequest bool `json:"withSignedRequest,omitempty"`
NameIDFormat *domain.SAMLNameIDFormat `json:"nameIDFormat,omitempty"`
TransientMappingAttributeName string `json:"transientMappingAttributeName,omitempty"`
FederatedLogoutEnabled bool `json:"federatedLogoutEnabled,omitempty"`
}
type IDPSAML struct {
*IdentityProvider
SAML
}
// IDPIdentifierCondition is used to help specify a single identity_provider, // IDPIdentifierCondition is used to help specify a single identity_provider,
// it will either be used as the identity_provider ID or identity_provider name, // it will either be used as the identity_provider ID or identity_provider name,
// as identity_provider can be identified either using (instanceID + OrgID + ID) OR (instanceID + OrgID + name) // as identity_provider can be identified either using (instanceID + OrgID + ID) OR (instanceID + OrgID + name)
@@ -316,4 +346,6 @@ type IDProviderRepository interface {
GetGitlab(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlab, error) GetGitlab(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlab, error)
GetGitlabSelfHosting(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlabSelfHosting, error) GetGitlabSelfHosting(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlabSelfHosting, error)
GetLDAP(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPLDAP, error) GetLDAP(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPLDAP, error)
GetApple(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPApple, error)
GetSAML(ctx context.Context, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPSAML, error)
} }

View File

@@ -14,6 +14,7 @@ import (
"github.com/zitadel/zitadel/backend/v3/domain" "github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
zitadel_internal_domain "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/idp" "github.com/zitadel/zitadel/pkg/grpc/idp"
idp_grpc "github.com/zitadel/zitadel/pkg/grpc/idp" idp_grpc "github.com/zitadel/zitadel/pkg/grpc/idp"
@@ -2140,4 +2141,297 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) {
assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute) assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute)
}, retryDuration, tick) }, retryDuration, tick)
}) })
t.Run("test instance apple added reduces", func(t *testing.T) {
name := gofakeit.Name()
// add apple
beforeCreate := time.Now()
// addApple, err := AdminClient.AddAppleProvider(CTX, &admin.AddAppleProviderRequest{
addApple, err := MgmtClient.AddAppleProvider(CTX, &management.AddAppleProviderRequest{
Name: name,
ClientId: "clientID",
TeamId: "teamIDteam",
KeyId: "keyIDKeyId",
PrivateKey: []byte("privateKey"),
Scopes: []string{"scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
afterCreate := time.Now()
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
apple, err := idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, &orgID)
require.NoError(t, err)
// event instance.idp.apple.added
// idp
assert.Equal(t, instanceID, apple.InstanceID)
assert.Equal(t, orgID, *apple.OrgID)
assert.Equal(t, addApple.Id, apple.ID)
assert.Equal(t, name, apple.Name)
assert.Equal(t, domain.IDPTypeApple.String(), apple.Type)
assert.Equal(t, false, apple.AllowLinking)
assert.Equal(t, false, apple.AllowCreation)
assert.Equal(t, false, apple.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), apple.AllowAutoLinking)
assert.WithinRange(t, apple.CreatedAt, beforeCreate, afterCreate)
assert.WithinRange(t, apple.UpdatedAt, beforeCreate, afterCreate)
// apple
assert.Equal(t, "clientID", apple.ClientID)
assert.Equal(t, "teamIDteam", apple.TeamID)
assert.Equal(t, "keyIDKeyId", apple.KeyID)
assert.NotNil(t, apple.PrivateKey)
assert.Equal(t, []string{"scope"}, apple.Scopes)
}, retryDuration, tick)
})
t.Run("test instance apple changed reduces", func(t *testing.T) {
name := gofakeit.Name()
// add apple
addApple, err := MgmtClient.AddAppleProvider(CTX, &management.AddAppleProviderRequest{
Name: name,
ClientId: "clientID",
TeamId: "teamIDteam",
KeyId: "keyIDKeyId",
PrivateKey: []byte("privateKey"),
Scopes: []string{"scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
var apple *domain.IDPApple
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
apple, err = idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, &orgID)
require.NoError(t, err)
assert.Equal(t, addApple.Id, apple.ID)
}, retryDuration, tick)
name = "new_" + name
// change apple
beforeCreate := time.Now()
// _, err = AdminClient.UpdateAppleProvider(CTX, &admin.UpdateAppleProviderRequest{
_, err = MgmtClient.UpdateAppleProvider(CTX, &management.UpdateAppleProviderRequest{
Id: addApple.Id,
Name: name,
ClientId: "new_clientID",
TeamId: "new_teamID",
KeyId: "new_kKeyId",
PrivateKey: []byte("new_privateKey"),
Scopes: []string{"new_scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: true,
IsCreationAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
},
})
afterCreate := time.Now()
require.NoError(t, err)
// check values for apple
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
updateApple, err := idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, &orgID)
require.NoError(t, err)
// event nstance.idp.apple.changed
// idp
assert.Equal(t, instanceID, updateApple.InstanceID)
assert.Equal(t, orgID, *updateApple.OrgID)
assert.Equal(t, addApple.Id, updateApple.ID)
assert.Equal(t, name, updateApple.Name)
assert.Equal(t, domain.IDPTypeApple.String(), updateApple.Type)
assert.Equal(t, true, updateApple.AllowLinking)
assert.Equal(t, true, updateApple.AllowCreation)
assert.Equal(t, true, updateApple.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateApple.AllowAutoLinking)
assert.WithinRange(t, updateApple.UpdatedAt, beforeCreate, afterCreate)
// apple
assert.Equal(t, "new_clientID", updateApple.ClientID)
assert.Equal(t, "new_teamID", updateApple.TeamID)
assert.Equal(t, "new_kKeyId", updateApple.KeyID)
assert.NotEqual(t, apple.PrivateKey, updateApple.PrivateKey)
assert.Equal(t, []string{"new_scope"}, updateApple.Scopes)
}, retryDuration, tick)
})
t.Run("test instance saml added reduces", func(t *testing.T) {
name := gofakeit.Name()
federatedLogoutEnabled := false
// add saml
beforeCreate := time.Now()
addSAML, err := MgmtClient.AddSAMLProvider(CTX, &management.AddSAMLProviderRequest{
Name: name,
Metadata: &management.AddSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata1,
},
Binding: idp.SAMLBinding_SAML_BINDING_POST,
WithSignedRequest: false,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
afterCreate := time.Now()
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
saml, err := idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, &orgID)
require.NoError(t, err)
// event instance.idp.saml.added
// idp
assert.Equal(t, instanceID, saml.InstanceID)
assert.Equal(t, orgID, *saml.OrgID)
assert.Equal(t, addSAML.Id, saml.ID)
assert.Equal(t, name, saml.Name)
assert.Equal(t, domain.IDPTypeSAML.String(), saml.Type)
assert.Equal(t, false, saml.AllowLinking)
assert.Equal(t, false, saml.AllowCreation)
assert.Equal(t, false, saml.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), saml.AllowAutoLinking)
assert.WithinRange(t, saml.CreatedAt, beforeCreate, afterCreate)
assert.WithinRange(t, saml.UpdatedAt, beforeCreate, afterCreate)
// saml
assert.Equal(t, validSAMLMetadata1, saml.Metadata)
assert.NotNil(t, saml.Key)
assert.NotNil(t, saml.Certificate)
assert.NotNil(t, saml.Binding)
assert.Equal(t, false, saml.WithSignedRequest)
assert.Equal(t, zitadel_internal_domain.SAMLNameIDFormatTransient, *saml.NameIDFormat)
assert.Equal(t, name, saml.TransientMappingAttributeName)
assert.Equal(t, false, saml.FederatedLogoutEnabled)
}, retryDuration, tick)
})
t.Run("test instance saml changed reduces", func(t *testing.T) {
name := gofakeit.Name()
federatedLogoutEnabled := false
// add saml
addSAML, err := MgmtClient.AddSAMLProvider(CTX, &management.AddSAMLProviderRequest{
Name: name,
// Metadata: &admin.AddSAMLProviderRequest_MetadataXml{
Metadata: &management.AddSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata1,
},
Binding: idp.SAMLBinding_SAML_BINDING_POST,
WithSignedRequest: false,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
var saml *domain.IDPSAML
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
saml, err = idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, &orgID)
require.NoError(t, err)
assert.Equal(t, addSAML.Id, saml.ID)
}, retryDuration, tick)
name = "new_" + name
federatedLogoutEnabled = true
// change saml
beforeCreate := time.Now()
_, err = MgmtClient.UpdateSAMLProvider(CTX, &management.UpdateSAMLProviderRequest{
Id: addSAML.Id,
Name: name,
// Metadata: &admin.UpdateSAMLProviderRequest_MetadataXml{
Metadata: &management.UpdateSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata2,
},
Binding: idp.SAMLBinding_SAML_BINDING_ARTIFACT,
WithSignedRequest: true,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_EMAIL_ADDRESS.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: true,
IsCreationAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
},
})
afterCreate := time.Now()
require.NoError(t, err)
// check values for apple
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
updateSAML, err := idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, &orgID)
require.NoError(t, err)
// event instance.idp.saml.changed
// idp
assert.Equal(t, instanceID, updateSAML.InstanceID)
assert.Equal(t, orgID, *updateSAML.OrgID)
assert.Equal(t, addSAML.Id, updateSAML.ID)
assert.Equal(t, name, updateSAML.Name)
assert.Equal(t, domain.IDPTypeSAML.String(), updateSAML.Type)
assert.Equal(t, true, updateSAML.AllowLinking)
assert.Equal(t, true, updateSAML.AllowCreation)
assert.Equal(t, true, updateSAML.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateSAML.AllowAutoLinking)
assert.WithinRange(t, updateSAML.UpdatedAt, beforeCreate, afterCreate)
// saml
assert.Equal(t, validSAMLMetadata2, updateSAML.Metadata)
assert.NotNil(t, updateSAML.Key)
// assert.NotEqual(t, saml.Key, updateSAML.Key) // https://github.com/zitadel/zitadel/issues/10414
assert.NotNil(t, updateSAML.Certificate)
// assert.NotEqual(t, saml.Certificate, updateSAML.Certificate) // https://github.com/zitadel/zitadel/issues/10414
assert.NotNil(t, updateSAML.Binding)
assert.NotEqual(t, saml.Binding, updateSAML.Binding)
assert.Equal(t, true, updateSAML.WithSignedRequest)
assert.Equal(t, zitadel_internal_domain.SAMLNameIDFormatEmailAddress, *updateSAML.NameIDFormat)
assert.Equal(t, name, updateSAML.TransientMappingAttributeName)
assert.Equal(t, true, updateSAML.FederatedLogoutEnabled)
}, retryDuration, tick)
})
} }

View File

@@ -13,6 +13,7 @@ import (
"github.com/zitadel/zitadel/backend/v3/domain" "github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database" "github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
zitadel_internal_domain "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/admin" "github.com/zitadel/zitadel/pkg/grpc/admin"
"github.com/zitadel/zitadel/pkg/grpc/idp" "github.com/zitadel/zitadel/pkg/grpc/idp"
@@ -20,6 +21,123 @@ import (
durationpb "google.golang.org/protobuf/types/known/durationpb" durationpb "google.golang.org/protobuf/types/known/durationpb"
) )
var validSAMLMetadata1 = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://localhost:8080/saml/v2/metadata" ID="_8b02ecf6-aea4-4eda-96c6-190551f05b07">
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
<SignatureMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod>
<Reference xmlns="http://www.w3.org/2000/09/xmldsig#" URI="#_8b02ecf6-aea4-4eda-96c6-190551f05b07">
<Transforms xmlns="http://www.w3.org/2000/09/xmldsig#">
<Transform xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
<Transform xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
<DigestValue xmlns="http://www.w3.org/2000/09/xmldsig#">Tyw4csdpNNq0E7wi5FXWdVNkdPNg+cM6kK21VB2+iF0=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">hWQSYmnBJENy/okk2qRDuHaZiyqpDsdV6BF9/T/LNjUh/8z4dV2NEZvkNhFEyQ+bqdj+NmRWvKqpg1dtgNJxQc32+IsLQvXNYyhMCtyG570/jaTOtm8daV4NKJyTV7SdwM6yfXgubz5YCRTyV13W2gBIFYppIRImIv5NDcjz+lEmWhnrkw8G2wRSFUY7VvkDn9rgsTzw/Pnsw6hlzpjGDYPMPx3ux3kjFVevdhFGNo+VC7t9ozruuGyH3yue9Re6FZoqa4oyWaPSOwei0ZH6UNqkX93Eo5Y49QKwaO8Rm+kWsOhdTqebVmCc+SpWbbrZbQj4nSLgWGlvCkZSivmH7ezr4Ol1ZkRetQ92UQ7xJS7E0y6uXAGvdgpDnyqHCOFfhTS6yqltHtc3m7JZex327xkv6e69uAEOSiv++sifVUIE0h/5u3hZLvwmTPrkoRVY4wgZ4ieb86QPvhw4UPeYapOhCBk5RfjoEFIeYwPUw5rtOlpTyeBJiKMpH1+mDAoa+8HQytZoMrnnY1s612vINtY7jU5igMwIk6MitQpRGibnBVBHRc2A6aE+XS333ganFK9hX6TzNkpHUb66NINDZ8Rgb1thn3MABArGlomtM5/enrAixWExZp70TSElor7SBdBW57H7OZCYUCobZuPRDLsCO6LLKeVrbdygWeRqr/o=</SignatureValue>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">MIIFIjCCAwqgAwIBAgICA7YwDQYJKoZIhvcNAQELBQAwLDEQMA4GA1UEChMHWklUQURFTDEYMBYGA1UEAxMPWklUQURFTCBTQU1MIENBMB4XDTI0MTEyNzEwMjc0NFoXDTI1MTEyNzE2Mjc0NFowMjEQMA4GA1UEChMHWklUQURFTDEeMBwGA1UEAxMVWklUQURFTCBTQU1MIG1ldGFkYXRhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApEpYT7EjbRBp0Hw7PGCiSgUoJtwd2nwZOhGy5WZVWvraAtHzW5ih2B6UwEShjwCmRJZeKYEN9JKJbpAy2EdL/l2rm/pArVNvSQu6sN4izz5p2rd9NfHAO3/EcvYdrelWLQj8WQx6LVM282Z4wbclp8Jz1y8Ow43352hGfFVc1x8gauoNl5MAy4kdbvs8UqihqcRmEyIOWl6UwTApb+XIRSRz0Yop99Fv9ALJwfUppsx+d4j9rlRDvrQJMJz7GC/19L9INTbY0HsVEiTltdAWHwREwrpwxNJQt42p3W/zpf1mjwXd3qNNDZAr1t2POPP4SXd598kabBZ3EMWGGxFw+NYYajyjG5EFOZw09FFJn2jIcovejvigfdqem5DGPECvHefqcqHkBPGukI3RaotXpAYyAGfnV7slVytSW484IX3KloAJLICbETbFGGsGQzIDw8rUqWyaOCOttw2fVNDyRFUMHrGe1PhJ9qA1If+KCWYD0iJqF03rIEhdrvNSdQNYkRa0DdtpacQLpzQtqsUioODqX0W3uzLceJEXLBbU0ZEk8mWZM/auwMo3ycPNXDVwrb6AkUKar+sqSumUuixw7da3KF1/mynh6M2Eo4NRB16oUiyN0EYrit/RRJjsTdH+71cj0V+8KqO88cBpmm+lO6x4RM5xpOf/EwwQHivxgRkCAwEAAaNIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFIzl7uckcPWldirXeOFL3rH6K8FLMA0GCSqGSIb3DQEBCwUAA4ICAQBz+7R99uX1Us9T4BB2RK3RD9K8Q5foNmxJ8GbxpOQFL8IG1DE3FqBssciJkOsKY+1+Y6eow2TgmD9MxfCY444C8k8YDDjxIcs+4dEaWMUxA6NoEy378ciy0U1E6rpYLxWYTxXmsELyODWwTrRNIiWfbBD2m0w9HYbK6QvX6IYQqYoTOJJ3WJKsMCeQ8XhQsJYNINZEq8RsERY/aikOlTWN7ax4Mkr3bfnz1euXGClExCOM6ej4m2I33i4nyYBvvRkRRZRQCfkAQ+5WFVZoVXrQHNe/Oifit7tfLaDuybcjgkzzY3o0YbczzbdV69fVoj53VpR3QQOB+PCF/VJPUMtUFPEC05yH76g24KVBiM/Ws8GaERW1AxgupHSmvTY3GSiwDXQ2NzgDxUHfRHo8rxenJdEcPlGM0DstbUONDSFGLwvGDiidUVtqj1UB4yGL26bgtmwf61G4qsTn9PJMWdRmCeeOf7fmloRxTA0EEey3bulBBHim466tWHUhgOP+g1X0iE7CnwL8aJ//CCiQOAv1O6x5RLyxrmVTehPLr1T8qvnBmxpmuYU0kfbYpO3tMVe7VLabBx0cYh7izClZKHhgEj1w4aE9tIk7nqVAwvVocT3io8RrcKixlnBrFd7RYIuF3+RsYC/kYEgnZYKAig5u2TySgGmJ7nIS24FYW68WDg==</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<IDPSSODescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" WantAuthnRequestsSigned="1" ID="_fd70402c-8a31-4a9a-a4a7-da526524c609" validUntil="2024-12-02T16:54:55.656Z" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<SingleSignOnService xmlns="urn:oasis:names:tc:SAML:2.0:metadata" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/saml/v2/SSO"></SingleSignOnService>
<SingleSignOnService xmlns="urn:oasis:names:tc:SAML:2.0:metadata" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/saml/v2/SSO"></SingleSignOnService>
<AttributeProfile>urn:oasis:names:tc:SAML:2.0:profiles:attribute:basic</AttributeProfile>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="Email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="SurName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="FullName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="UserName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="UserID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<SingleLogoutService xmlns="urn:oasis:names:tc:SAML:2.0:metadata" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/saml/v2/SLO"></SingleLogoutService>
<SingleLogoutService xmlns="urn:oasis:names:tc:SAML:2.0:metadata" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/saml/v2/SLO"></SingleLogoutService>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<KeyDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>http://localhost:8080/saml/v2/metadata IDP signing</KeyName>
<X509Data xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">MIIFIjCCAwqgAwIBAgICA7QwDQYJKoZIhvcNAQELBQAwLDEQMA4GA1UEChMHWklUQURFTDEYMBYGA1UEAxMPWklUQURFTCBTQU1MIENBMB4XDTI0MTEyNzEwMjUwMloXDTI1MTEyNzE2MjUwMlowMjEQMA4GA1UEChMHWklUQURFTDEeMBwGA1UEAxMVWklUQURFTCBTQU1MIHJlc3BvbnNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2lUgaI6AS/9xvM9DNSWK6Ho64LpK8UIioM26QfvAfeQ/I2pgX6SwWxEbd7qv+PkJzaFTjrXSlwOmWsJYma+UsdyFClaGFRyCgY8SWxPceandC8a+hQIDS/irLd9XF33RWp0b/09HjQl+n0HZ4teUFDUd2U1mUf3XCpn0+Ho316bmi6xSW6zaMy5RsbUl01hgWj2fgapAsGAHSBphwCE3Dz/9I/UfHWQw1k2/UTgjc9uIujcza6WgOxfsKluXYIOxwNKTfmzzOJMUwXz6GRgB2jhQI29MuKOZOITA7pXq5kZKf0lSRU8zKFTMJaK4zAHQ6f877Drr8XdAHemuXGZ2JdH/Dbdwarzy3YBMCWsAYlpeEvaVAdiSpyR7fAZktNuHd39Zg00Vlj2wdc44Vk5yVssW7pv5qnVZ7JTrXX2uBYFecLAXmplQ2ph1VdSXZLEDGgjiNA2T/fBj7G4/VjsuCBZFm1I0KCJp3HWEJx5dwwhSVc5wOJEzl7fMuPYMKWH/RM6P/7LnO1ulpdmiKPa4gHzdg3hDZn42NKcVt3UYf0phtxpWMrZp/DUEeizhckrC4ed6cfGtS3CUtJEqoycrCROJ5Hy+ONHl5Aqxt+JoPU+t/XATuctfPxQVcDr0itHzo2cjh/AVTU+IC7C0oQHSS9CC8Fp58UqbtYwFtSAd7ecCAwEAAaNIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFIzl7uckcPWldirXeOFL3rH6K8FLMA0GCSqGSIb3DQEBCwUAA4ICAQAp+IGZScVIbRdCq5HPjlYBPOY7UbL8ZXnlMW/HLELV9GndnULuFhnuQTIdA5dquCsk8RI1fKsScEV1rqWvHZeSo5nVbvUaPJctoD/4GACqE6F8axs1AgSOvpJMyuycjSzSh6gDM1z37Fdqc/2IRqgi7SKdDsfJpi8XW8LtErpp4kyE1rEXopsXG2fe1UH25bZpXraUqYvp61rwVUCazAtV/U7ARG5AnT0mPqzUriIPrfL+v/+2ntV/BSc8/uCqYnHbwpIwjPURCaxo1Pmm6EEkm+V/Ss4ieNwwkD2bLLLST1LoVMim7Ebfy53PEKpsznKsGlVSu0YYKUsStWQVpwhKQw0bQLCJHdpvZtZSDgS9RbSMZz+aY/fpoNx6wDvmMgtdrb3pVXZ8vPKdq9YDrGfFqP60QdZ3CuSHXCM/zX4742GgImJ4KYAcTuF1+BkGf5JLAJOUZBkfCQ/kBT5wr8+EotLxASOC6717whLBYMEG6N8osEk+LDqoJRTLqkzirJsyOHWChKK47yGkdS3HBIZfo91QrJwKpfATYziBjEnqipkTu+6jFylBIkxKTPye4b3vgcodZP8LSNVXAsMGTPNPJxzPWQ37ba4zMnYZ5iUerlaox/SNsn68DT6RajIb1A1JDq+HNFc3hQP2bzk2y5pCax8zo5swjdklnm4clfB2Lw==</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
</IDPSSODescriptor>
<AttributeAuthorityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" ID="_b3fed381-af56-4160-abf5-5ffd1e21cf61" validUntil="2024-12-02T16:54:55.656Z" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<AttributeService xmlns="urn:oasis:names:tc:SAML:2.0:metadata" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8080/saml/v2/attribute"></AttributeService>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<AttributeProfile>urn:oasis:names:tc:SAML:2.0:profiles:attribute:basic</AttributeProfile>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="Email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="SurName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="FullName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="UserName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<Attribute xmlns="urn:oasis:names:tc:SAML:2.0:assertion" Name="UserID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><AttributeValue></AttributeValue></Attribute>
<KeyDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" use="signing">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>http://localhost:8080/saml/v2/metadata IDP signing</KeyName>
<X509Data xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Certificate xmlns="http://www.w3.org/2000/09/xmldsig#">MIIFIjCCAwqgAwIBAgICA7QwDQYJKoZIhvcNAQELBQAwLDEQMA4GA1UEChMHWklUQURFTDEYMBYGA1UEAxMPWklUQURFTCBTQU1MIENBMB4XDTI0MTEyNzEwMjUwMloXDTI1MTEyNzE2MjUwMlowMjEQMA4GA1UEChMHWklUQURFTDEeMBwGA1UEAxMVWklUQURFTCBTQU1MIHJlc3BvbnNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2lUgaI6AS/9xvM9DNSWK6Ho64LpK8UIioM26QfvAfeQ/I2pgX6SwWxEbd7qv+PkJzaFTjrXSlwOmWsJYma+UsdyFClaGFRyCgY8SWxPceandC8a+hQIDS/irLd9XF33RWp0b/09HjQl+n0HZ4teUFDUd2U1mUf3XCpn0+Ho316bmi6xSW6zaMy5RsbUl01hgWj2fgapAsGAHSBphwCE3Dz/9I/UfHWQw1k2/UTgjc9uIujcza6WgOxfsKluXYIOxwNKTfmzzOJMUwXz6GRgB2jhQI29MuKOZOITA7pXq5kZKf0lSRU8zKFTMJaK4zAHQ6f877Drr8XdAHemuXGZ2JdH/Dbdwarzy3YBMCWsAYlpeEvaVAdiSpyR7fAZktNuHd39Zg00Vlj2wdc44Vk5yVssW7pv5qnVZ7JTrXX2uBYFecLAXmplQ2ph1VdSXZLEDGgjiNA2T/fBj7G4/VjsuCBZFm1I0KCJp3HWEJx5dwwhSVc5wOJEzl7fMuPYMKWH/RM6P/7LnO1ulpdmiKPa4gHzdg3hDZn42NKcVt3UYf0phtxpWMrZp/DUEeizhckrC4ed6cfGtS3CUtJEqoycrCROJ5Hy+ONHl5Aqxt+JoPU+t/XATuctfPxQVcDr0itHzo2cjh/AVTU+IC7C0oQHSS9CC8Fp58UqbtYwFtSAd7ecCAwEAAaNIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFIzl7uckcPWldirXeOFL3rH6K8FLMA0GCSqGSIb3DQEBCwUAA4ICAQAp+IGZScVIbRdCq5HPjlYBPOY7UbL8ZXnlMW/HLELV9GndnULuFhnuQTIdA5dquCsk8RI1fKsScEV1rqWvHZeSo5nVbvUaPJctoD/4GACqE6F8axs1AgSOvpJMyuycjSzSh6gDM1z37Fdqc/2IRqgi7SKdDsfJpi8XW8LtErpp4kyE1rEXopsXG2fe1UH25bZpXraUqYvp61rwVUCazAtV/U7ARG5AnT0mPqzUriIPrfL+v/+2ntV/BSc8/uCqYnHbwpIwjPURCaxo1Pmm6EEkm+V/Ss4ieNwwkD2bLLLST1LoVMim7Ebfy53PEKpsznKsGlVSu0YYKUsStWQVpwhKQw0bQLCJHdpvZtZSDgS9RbSMZz+aY/fpoNx6wDvmMgtdrb3pVXZ8vPKdq9YDrGfFqP60QdZ3CuSHXCM/zX4742GgImJ4KYAcTuF1+BkGf5JLAJOUZBkfCQ/kBT5wr8+EotLxASOC6717whLBYMEG6N8osEk+LDqoJRTLqkzirJsyOHWChKK47yGkdS3HBIZfo91QrJwKpfATYziBjEnqipkTu+6jFylBIkxKTPye4b3vgcodZP8LSNVXAsMGTPNPJxzPWQ37ba4zMnYZ5iUerlaox/SNsn68DT6RajIb1A1JDq+HNFc3hQP2bzk2y5pCax8zo5swjdklnm4clfB2Lw==</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
</AttributeAuthorityDescriptor>
</EntityDescriptor>`)
var validSAMLMetadata2 = []byte(`<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://idp-saml.ua3.int/simplesaml/saml2/idp/metadata.php">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIID7TCCAtWgAwIBAgIJANn3qP9lF7M3MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVQTEXMBUGA1UE
CAwOS2hhcmtpdiBSZWdpb24xEDAOBgNVBAcMB0toYXJrb3YxDzANBgNVBAoMBk9yYWNsZTEYMBYGA1UEAwwPc3RzeWJvdi12bTEudWEzMScw
JQYJKoZIhvcNAQkBFhhzZXJnaWkudHN5Ym92QG9yYWNsZS5jb20wHhcNMTUxMjI1MTIyMjU5WhcNMjUxMjI0MTIyMjU5WjCBjDELMAkGA1UE
BhMCVUExFzAVBgNVBAgMDktoYXJraXYgUmVnaW9uMRAwDgYDVQQHDAdLaGFya292MQ8wDQYDVQQKDAZPcmFjbGUxGDAWBgNVBAMMD3N0c3lib
3Ytdm0xLnVhMzEnMCUGCSqGSIb3DQEJARYYc2VyZ2lpLnRzeWJvdkBvcmFjbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCA
QEAw4OFwuUNjn6xxb/OuAnmQA6mCWPY2hKMoOz0cAajUHjNZZMwGnuEeUyPtEcULfz2MYo1yKQLxVj3pY0HTIQAzpY8o+xCqJFQmdMiakb
PFHlh4z/qqiS5jHng6JCeUpCIxeiTG9JXVwF1ErBEZbwZYjVxa6S+0grVkS3YxuH4uTyqxskuGnHK/AviTHLBrLfSrbFKYuQUrXyy6X22wpzo
bQ3Z+4bhEE8SXQtVbQdy7K0MKWYopNhX05SMTv7yMfUGp8EkGNyJ5Km8AuQt6ZCbVao6cHL2hSujQiN6aMjKbdzHeA1QEicppnnoG/Zefyi/
okWdlLAaLjcpYrjUSWQJZQIDAQABo1AwTjAdBgNVHQ4EFgQUIKa0zeXmAJsCuNhJjhU0o7KiQgYwHwYDVR0jBBgwFoAUIKa0zeXmAJsCuNhJj
hU0o7KiQgYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAJawU5WRXqkW4emm+djpJAxZ0076qPgEsaaog6ng4MLAlU7RmfIY/
l0VhXQegvhIBfG4OfduuzGaqd9y4IsQZFJ0yuotl96iEVcqg7hJ1LEY6UT6u6dZyGj1a9I6IlwJm/9CXFZHuVqGJkMfQZ4gaunE4c5gjbQA5/
+PEJwPorKn48w8bojymV8hriqzrmaP8eQNuZUJsJdnKENOE5/asGyj+R2YfP6bmlOX3q0ozLcyJbXeZ6IvDFdRiDH5wO4JqW/ujvdvC553y
CO3xxsorB4xCupuHu/c7vkzNpaKjYdmGRkqhEqBcCqYSxdwIFc1xhOwYPWKJzgn7pGQsT7yNJg==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIID7TCCAtWgAwIBAgIJANn3qP9lF7M3MA0GCSqGSIb3DQEBCwUAMIGMMQswCQYDVQQGEwJVQTEXMBUGA1
UECAwOS2hhcmtpdiBSZWdpb24xEDAOBgNVBAcMB0toYXJrb3YxDzANBgNVBAoMBk9yYWNsZTEYMBYGA1UEAwwPc3RzeWJvdi12bTEud
WEzMScwJQYJKoZIhvcNAQkBFhhzZXJnaWkudHN5Ym92QG9yYWNsZS5jb20wHhcNMTUxMjI1MTIyMjU5WhcNMjUxMjI0MTIyMjU5WjCB
jDELMAkGA1UEBhMCVUExFzAVBgNVBAgMDktoYXJraXYgUmVnaW9uMRAwDgYDVQQHDAdLaGFya292MQ8wDQYDVQQKDAZPcmFjbGUxGDA
WBgNVBAMMD3N0c3lib3Ytdm0xLnVhMzEnMCUGCSqGSIb3DQEJARYYc2VyZ2lpLnRzeWJvdkBvcmFjbGUuY29tMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAw4OFwuUNjn6xxb/OuAnmQA6mCWPY2hKMoOz0cAajUHjNZZMwGnuEeUyPtEcULfz2MYo1yKQLxVj3pY0HT
IQAzpY8o+xCqJFQmdMiakbPFHlh4z/qqiS5jHng6JCeUpCIxeiTG9JXVwF1ErBEZbwZYjVxa6S+0grVkS3YxuH4uTyqxskuGnHK/
AviTHLBrLfSrbFKYuQUrXyy6X22wpzobQ3Z+4bhEE8SXQtVbQdy7K0MKWYopNhX05SMTv7yMfUGp8EkGNyJ5Km8AuQt6ZCbVao6cHL2h
SujQiN6aMjKbdzHeA1QEicppnnoG/Zefyi/okWdlLAaLjcpYrjUSWQJZQIDAQABo1AwTjAdBgNVHQ4EFgQUIKa0zeXmAJsCuNhJjhU0o
7KiQgYwHwYDVR0jBBgwFoAUIKa0zeXmAJsCuNhJjhU0o7KiQgYwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAJawU5WRXq
kW4emm+djpJAxZ0076qPgEsaaog6ng4MLAlU7RmfIY/l0VhXQegvhIBfG4OfduuzGaqd9y4IsQZFJ0yuotl96iEVcqg7hJ1LEY6UT6u6d
ZyGj1a9I6IlwJm/9CXFZHuVqGJkMfQZ4gaunE4c5gjbQA5/+PEJwPorKn48w8bojymV8hriqzrmaP8eQNuZUJsJdnKENOE5/
asGyj+R2YfP6bmlOX3q0ozLcyJbXeZ6IvDFdRiDH5wO4JqW/ujvdvC553yCO3xxsorB4xCupuHu/c7vkzNpaKjYdmGRkqhEqBcCqYSxd
wIFc1xhOwYPWKJzgn7pGQsT7yNJg==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp-saml.ua3.int/simplesaml/saml2/idp/SingleLogoutService.php"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://idp-saml.ua3.int/simplesaml/saml2/idp/SSOService.php"/>
</md:IDPSSODescriptor>
<md:ContactPerson contactType="technical">
<md:SurName>Administrator</md:SurName>
<md:EmailAddress>name@emailprovider.com</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>`)
func TestServer_TestIDProviderReduces(t *testing.T) { func TestServer_TestIDProviderReduces(t *testing.T) {
instanceID := Instance.ID() instanceID := Instance.ID()
@@ -2102,4 +2220,293 @@ func TestServer_TestIDProviderReduces(t *testing.T) {
assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute) assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute)
}, retryDuration, tick) }, retryDuration, tick)
}) })
t.Run("test instance apple added reduces", func(t *testing.T) {
name := gofakeit.Name()
// add apple
beforeCreate := time.Now()
addApple, err := AdminClient.AddAppleProvider(CTX, &admin.AddAppleProviderRequest{
Name: name,
ClientId: "clientID",
TeamId: "teamIDteam",
KeyId: "keyIDKeyId",
PrivateKey: []byte("privateKey"),
Scopes: []string{"scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
afterCreate := time.Now()
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
apple, err := idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, nil)
require.NoError(t, err)
// event instance.idp.apple.added
// idp
assert.Equal(t, instanceID, apple.InstanceID)
assert.Nil(t, apple.OrgID)
assert.Equal(t, addApple.Id, apple.ID)
assert.Equal(t, name, apple.Name)
assert.Equal(t, domain.IDPTypeApple.String(), apple.Type)
assert.Equal(t, false, apple.AllowLinking)
assert.Equal(t, false, apple.AllowCreation)
assert.Equal(t, false, apple.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), apple.AllowAutoLinking)
assert.WithinRange(t, apple.CreatedAt, beforeCreate, afterCreate)
assert.WithinRange(t, apple.UpdatedAt, beforeCreate, afterCreate)
// apple
assert.Equal(t, "clientID", apple.ClientID)
assert.Equal(t, "teamIDteam", apple.TeamID)
assert.Equal(t, "keyIDKeyId", apple.KeyID)
assert.NotNil(t, apple.PrivateKey)
assert.Equal(t, []string{"scope"}, apple.Scopes)
}, retryDuration, tick)
})
t.Run("test instance apple changed reduces", func(t *testing.T) {
name := gofakeit.Name()
// add apple
addApple, err := AdminClient.AddAppleProvider(CTX, &admin.AddAppleProviderRequest{
Name: name,
ClientId: "clientID",
TeamId: "teamIDteam",
KeyId: "keyIDKeyId",
PrivateKey: []byte("privateKey"),
Scopes: []string{"scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
var apple *domain.IDPApple
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
apple, err = idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, nil)
require.NoError(t, err)
assert.Equal(t, addApple.Id, apple.ID)
}, retryDuration, tick)
name = "new_" + name
// change apple
beforeCreate := time.Now()
_, err = AdminClient.UpdateAppleProvider(CTX, &admin.UpdateAppleProviderRequest{
Id: addApple.Id,
Name: name,
ClientId: "new_clientID",
TeamId: "new_teamID",
KeyId: "new_kKeyId",
PrivateKey: []byte("new_privateKey"),
Scopes: []string{"new_scope"},
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: true,
IsCreationAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
},
})
afterCreate := time.Now()
require.NoError(t, err)
// check values for apple
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
updateApple, err := idpRepo.GetApple(CTX, idpRepo.IDCondition(addApple.Id), instanceID, nil)
require.NoError(t, err)
// event nstance.idp.apple.changed
// idp
assert.Equal(t, instanceID, updateApple.InstanceID)
assert.Nil(t, updateApple.OrgID)
assert.Equal(t, addApple.Id, updateApple.ID)
assert.Equal(t, name, updateApple.Name)
assert.Equal(t, domain.IDPTypeApple.String(), updateApple.Type)
assert.Equal(t, true, updateApple.AllowLinking)
assert.Equal(t, true, updateApple.AllowCreation)
assert.Equal(t, true, updateApple.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateApple.AllowAutoLinking)
assert.WithinRange(t, updateApple.UpdatedAt, beforeCreate, afterCreate)
// apple
assert.Equal(t, "new_clientID", updateApple.ClientID)
assert.Equal(t, "new_teamID", updateApple.TeamID)
assert.Equal(t, "new_kKeyId", updateApple.KeyID)
assert.NotEqual(t, apple.PrivateKey, updateApple.PrivateKey)
assert.Equal(t, []string{"new_scope"}, updateApple.Scopes)
}, retryDuration, tick)
})
t.Run("test instance saml added reduces", func(t *testing.T) {
name := gofakeit.Name()
federatedLogoutEnabled := false
// add saml
beforeCreate := time.Now()
addSAML, err := AdminClient.AddSAMLProvider(CTX, &admin.AddSAMLProviderRequest{
Name: name,
Metadata: &admin.AddSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata1,
},
Binding: idp.SAMLBinding_SAML_BINDING_POST,
WithSignedRequest: false,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
afterCreate := time.Now()
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
saml, err := idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, nil)
require.NoError(t, err)
// event instance.idp.saml.added
// idp
assert.Equal(t, instanceID, saml.InstanceID)
assert.Nil(t, saml.OrgID)
assert.Equal(t, addSAML.Id, saml.ID)
assert.Equal(t, name, saml.Name)
assert.Equal(t, domain.IDPTypeSAML.String(), saml.Type)
assert.Equal(t, false, saml.AllowLinking)
assert.Equal(t, false, saml.AllowCreation)
assert.Equal(t, false, saml.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionEmail.String(), saml.AllowAutoLinking)
assert.WithinRange(t, saml.CreatedAt, beforeCreate, afterCreate)
assert.WithinRange(t, saml.UpdatedAt, beforeCreate, afterCreate)
// saml
assert.Equal(t, validSAMLMetadata1, saml.Metadata)
assert.NotNil(t, saml.Key)
assert.NotNil(t, saml.Certificate)
assert.NotNil(t, saml.Binding)
assert.Equal(t, false, saml.WithSignedRequest)
assert.Equal(t, zitadel_internal_domain.SAMLNameIDFormatTransient, *saml.NameIDFormat)
assert.Equal(t, name, saml.TransientMappingAttributeName)
assert.Equal(t, false, saml.FederatedLogoutEnabled)
}, retryDuration, tick)
})
t.Run("test instance saml changed reduces", func(t *testing.T) {
name := gofakeit.Name()
federatedLogoutEnabled := false
// add saml
addSAML, err := AdminClient.AddSAMLProvider(CTX, &admin.AddSAMLProviderRequest{
Name: name,
Metadata: &admin.AddSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata1,
},
Binding: idp.SAMLBinding_SAML_BINDING_POST,
WithSignedRequest: false,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: false,
IsCreationAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
})
require.NoError(t, err)
idpRepo := repository.IDProviderRepository(pool)
var saml *domain.IDPSAML
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
saml, err = idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, nil)
require.NoError(t, err)
assert.Equal(t, addSAML.Id, saml.ID)
}, retryDuration, tick)
name = "new_" + name
federatedLogoutEnabled = true
// change saml
beforeCreate := time.Now()
_, err = AdminClient.UpdateSAMLProvider(CTX, &admin.UpdateSAMLProviderRequest{
Id: addSAML.Id,
Name: name,
Metadata: &admin.UpdateSAMLProviderRequest_MetadataXml{
MetadataXml: validSAMLMetadata2,
},
Binding: idp.SAMLBinding_SAML_BINDING_ARTIFACT,
WithSignedRequest: true,
TransientMappingAttributeName: &name,
FederatedLogoutEnabled: &federatedLogoutEnabled,
NameIdFormat: idp.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_EMAIL_ADDRESS.Enum(),
ProviderOptions: &idp_grpc.Options{
IsLinkingAllowed: true,
IsCreationAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
},
})
afterCreate := time.Now()
require.NoError(t, err)
// check values for apple
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(CTX, time.Second*5)
assert.EventuallyWithT(t, func(t *assert.CollectT) {
updateSAML, err := idpRepo.GetSAML(CTX, idpRepo.IDCondition(addSAML.Id), instanceID, nil)
require.NoError(t, err)
// event instance.idp.saml.changed
// idp
assert.Equal(t, instanceID, updateSAML.InstanceID)
assert.Nil(t, updateSAML.OrgID)
assert.Equal(t, addSAML.Id, updateSAML.ID)
assert.Equal(t, name, updateSAML.Name)
assert.Equal(t, domain.IDPTypeSAML.String(), updateSAML.Type)
assert.Equal(t, true, updateSAML.AllowLinking)
assert.Equal(t, true, updateSAML.AllowCreation)
assert.Equal(t, true, updateSAML.AllowAutoUpdate)
assert.Equal(t, domain.IDPAutoLinkingOptionUserName.String(), updateSAML.AllowAutoLinking)
assert.WithinRange(t, updateSAML.UpdatedAt, beforeCreate, afterCreate)
// saml
assert.Equal(t, validSAMLMetadata2, updateSAML.Metadata)
assert.NotNil(t, updateSAML.Key)
// assert.NotEqual(t, saml.Key, updateSAML.Key) // https://github.com/zitadel/zitadel/issues/10414
assert.NotNil(t, updateSAML.Certificate)
// assert.NotEqual(t, saml.Certificate, updateSAML.Certificate) // https://github.com/zitadel/zitadel/issues/10414
assert.NotNil(t, updateSAML.Binding)
assert.NotEqual(t, saml.Binding, updateSAML.Binding)
assert.Equal(t, true, updateSAML.WithSignedRequest)
assert.Equal(t, zitadel_internal_domain.SAMLNameIDFormatEmailAddress, *updateSAML.NameIDFormat)
assert.Equal(t, name, updateSAML.TransientMappingAttributeName)
assert.Equal(t, true, updateSAML.FederatedLogoutEnabled)
}, retryDuration, tick)
})
} }

View File

@@ -339,6 +339,50 @@ func (i *idProvider) GetLDAP(ctx context.Context, id domain.IDPIdentifierConditi
return ldap, nil return ldap, nil
} }
func (i *idProvider) GetApple(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IDPApple, error) {
apple := &domain.IDPApple{}
var err error
apple.IdentityProvider, err = i.Get(ctx, id, instnaceID, orgID)
if err != nil {
return nil, err
}
if apple.Type != domain.IDPTypeApple.String() {
// TODO
return nil, errors.New("WRONG TYPE")
}
err = json.Unmarshal([]byte(*apple.Payload), apple)
if err != nil {
return nil, err
}
return apple, nil
}
func (i *idProvider) GetSAML(ctx context.Context, id domain.IDPIdentifierCondition, instnaceID string, orgID *string) (*domain.IDPSAML, error) {
saml := &domain.IDPSAML{}
var err error
saml.IdentityProvider, err = i.Get(ctx, id, instnaceID, orgID)
if err != nil {
return nil, err
}
if saml.Type != domain.IDPTypeSAML.String() {
// TODO
return nil, errors.New("WRONG TYPE")
}
err = json.Unmarshal([]byte(*saml.Payload), saml)
if err != nil {
return nil, err
}
return saml, nil
}
// ------------------------------------------------------------- // -------------------------------------------------------------
// columns // columns
// ------------------------------------------------------------- // -------------------------------------------------------------

View File

@@ -3,7 +3,9 @@ package projection
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres" "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository" "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
@@ -164,30 +166,30 @@ func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer
Event: instance.LDAPIDPChangedEventType, Event: instance.LDAPIDPChangedEventType,
Reduce: p.reduceLDAPIDPChanged, Reduce: p.reduceLDAPIDPChanged,
}, },
// { {
// Event: instance.AppleIDPAddedEventType, Event: instance.AppleIDPAddedEventType,
// Reduce: p.reduceAppleIDPAdded, Reduce: p.reduceAppleIDPAdded,
// }, },
// { {
// Event: instance.AppleIDPChangedEventType, Event: instance.AppleIDPChangedEventType,
// Reduce: p.reduceAppleIDPChanged, Reduce: p.reduceAppleIDPChanged,
// }, },
// { {
// Event: instance.SAMLIDPAddedEventType, Event: instance.SAMLIDPAddedEventType,
// Reduce: p.reduceSAMLIDPAdded, Reduce: p.reduceSAMLIDPAdded,
// }, },
// { {
// Event: instance.SAMLIDPChangedEventType, Event: instance.SAMLIDPChangedEventType,
// Reduce: p.reduceSAMLIDPChanged, Reduce: p.reduceSAMLIDPChanged,
// }, },
// { // {
// Event: instance.IDPConfigRemovedEventType, // Event: instance.IDPConfigRemovedEventType,
// Reduce: p.reduceIDPConfigRemoved, // Reduce: p.reduceIDPConfigRemoved,
// }, // },
// { {
// Event: instance.IDPRemovedEventType, Event: instance.IDPRemovedEventType,
// Reduce: p.reduceIDPRemoved, Reduce: p.reduceIDPRemoved,
// }, },
// { // {
// Event: instance.InstanceRemovedEventType, // Event: instance.InstanceRemovedEventType,
// Reduce: reduceInstanceRemovedHelper(IDPTemplateInstanceIDCol), // Reduce: reduceInstanceRemovedHelper(IDPTemplateInstanceIDCol),
@@ -309,30 +311,30 @@ func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer
Event: org.LDAPIDPChangedEventType, Event: org.LDAPIDPChangedEventType,
Reduce: p.reduceLDAPIDPChanged, Reduce: p.reduceLDAPIDPChanged,
}, },
// { {
// Event: org.AppleIDPAddedEventType, Event: org.AppleIDPAddedEventType,
// Reduce: p.reduceAppleIDPAdded, Reduce: p.reduceAppleIDPAdded,
// }, },
// { {
// Event: org.AppleIDPChangedEventType, Event: org.AppleIDPChangedEventType,
// Reduce: p.reduceAppleIDPChanged, Reduce: p.reduceAppleIDPChanged,
// }, },
// { {
// Event: org.SAMLIDPAddedEventType, Event: org.SAMLIDPAddedEventType,
// Reduce: p.reduceSAMLIDPAdded, Reduce: p.reduceSAMLIDPAdded,
// }, },
// { {
// Event: org.SAMLIDPChangedEventType, Event: org.SAMLIDPChangedEventType,
// Reduce: p.reduceSAMLIDPChanged, Reduce: p.reduceSAMLIDPChanged,
// }, },
// { // {
// Event: org.IDPConfigRemovedEventType, // Event: org.IDPConfigRemovedEventType,
// Reduce: p.reduceIDPConfigRemoved, // Reduce: p.reduceIDPConfigRemoved,
// }, // },
// { {
// Event: org.IDPRemovedEventType, Event: org.IDPRemovedEventType,
// Reduce: p.reduceIDPRemoved, Reduce: p.reduceIDPRemoved,
// }, },
// { // {
// Event: org.OrgRemovedEventType, // Event: org.OrgRemovedEventType,
// Reduce: p.reduceOwnerRemoved, // Reduce: p.reduceOwnerRemoved,
@@ -1862,195 +1864,235 @@ func (p *idpTemplateRelationalProjection) reduceLDAPIDPChanged(event eventstore.
// ), nil // ), nil
} }
// func (p *idpTemplateProjection) reduceSAMLIDPAdded(event eventstore.Event) (*handler.Statement, error) { func (p *idpTemplateRelationalProjection) reduceAppleIDPAdded(event eventstore.Event) (*handler.Statement, error) {
// var idpEvent idp.SAMLIDPAddedEvent var idpEvent idp.AppleIDPAddedEvent
// var idpOwnerType domain.IdentityProviderType switch e := event.(type) {
// switch e := event.(type) { case *org.AppleIDPAddedEvent:
// case *org.SAMLIDPAddedEvent: idpEvent = e.AppleIDPAddedEvent
// idpEvent = e.SAMLIDPAddedEvent case *instance.AppleIDPAddedEvent:
// idpOwnerType = domain.IdentityProviderTypeOrg idpEvent = e.AppleIDPAddedEvent
// case *instance.SAMLIDPAddedEvent: default:
// idpEvent = e.SAMLIDPAddedEvent return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YFvg3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPAddedEventType /*, instance.AppleIDPAddedEventType*/})
// idpOwnerType = domain.IdentityProviderTypeSystem }
// default:
// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPAddedEventType, instance.SAMLIDPAddedEventType})
// }
// columns := []handler.Column{ apple := db_domain.Apple{
// handler.NewCol(SAMLIDCol, idpEvent.ID), ClientID: idpEvent.ClientID,
// handler.NewCol(SAMLInstanceIDCol, idpEvent.Aggregate().InstanceID), TeamID: idpEvent.TeamID,
// handler.NewCol(SAMLMetadataCol, idpEvent.Metadata), KeyID: idpEvent.KeyID,
// handler.NewCol(SAMLKeyCol, idpEvent.Key), PrivateKey: idpEvent.PrivateKey,
// handler.NewCol(SAMLCertificateCol, idpEvent.Certificate), Scopes: idpEvent.Scopes,
// handler.NewCol(SAMLBindingCol, idpEvent.Binding), }
// handler.NewCol(SAMLWithSignedRequestCol, idpEvent.WithSignedRequest),
// handler.NewCol(SAMLTransientMappingAttributeName, idpEvent.TransientMappingAttributeName),
// handler.NewCol(SAMLFederatedLogoutEnabled, idpEvent.FederatedLogoutEnabled),
// }
// if idpEvent.NameIDFormat != nil {
// columns = append(columns, handler.NewCol(SAMLNameIDFormatCol, *idpEvent.NameIDFormat))
// }
// return handler.NewMultiStatement( payload, err := json.Marshal(apple)
// &idpEvent, if err != nil {
// handler.AddCreateStatement( return nil, err
// []handler.Column{ }
// handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()),
// handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
// handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
// handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner),
// handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive),
// handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
// handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType),
// handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeSAML),
// handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
// handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
// handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
// handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
// handler.NewCol(IDPTemplateAutoLinkingCol, idpEvent.AutoLinkingOption),
// },
// ),
// handler.AddCreateStatement(
// columns,
// handler.WithTableSuffix(IDPTemplateSAMLSuffix),
// ),
// ), nil
// }
// func (p *idpTemplateProjection) reduceSAMLIDPChanged(event eventstore.Event) (*handler.Statement, error) { var orgId *string
// var idpEvent idp.SAMLIDPChangedEvent if idpEvent.Aggregate().ResourceOwner != idpEvent.Agg.InstanceID {
// switch e := event.(type) { orgId = &idpEvent.Aggregate().ResourceOwner
// case *org.SAMLIDPChangedEvent: }
// idpEvent = e.SAMLIDPChangedEvent
// case *instance.SAMLIDPChangedEvent:
// idpEvent = e.SAMLIDPChangedEvent
// default:
// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-o7c0fii4ad", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPChangedEventType, instance.SAMLIDPChangedEventType})
// }
// ops := make([]func(eventstore.Event) handler.Exec, 0, 2) return handler.NewMultiStatement(
// ops = append(ops, &idpEvent,
// handler.AddUpdateStatement( handler.AddCreateStatement(
// reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges), []handler.Column{
// []handler.Condition{ handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCond(IDPTemplateIDCol, idpEvent.ID), handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), handler.NewCol(IDPRelationalOrgId, orgId),
// }, handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
// ), handler.NewCol(IDPTemplateTypeCol, db_domain.IDPTypeApple.String()),
// ) handler.NewCol(IDPTemplateStateCol, db_domain.IDPStateActive.String()),
handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
handler.NewCol(IDPRelationalAllowAutoLinkingCol, db_domain.IDPAutoLinkingOption(idpEvent.AutoLinkingOption).String()),
handler.NewCol(CreatedAt, idpEvent.CreationDate()),
handler.NewCol(IDPRelationalPayloadCol, payload),
},
),
), nil
}
// SAMLCols := reduceSAMLIDPChangedColumns(idpEvent) func (p *idpTemplateRelationalProjection) reduceAppleIDPChanged(event eventstore.Event) (*handler.Statement, error) {
// if len(SAMLCols) > 0 { var idpEvent idp.AppleIDPChangedEvent
// ops = append(ops, switch e := event.(type) {
// handler.AddUpdateStatement( case *org.AppleIDPChangedEvent:
// SAMLCols, idpEvent = e.AppleIDPChangedEvent
// []handler.Condition{ case *instance.AppleIDPChangedEvent:
// handler.NewCond(SAMLIDCol, idpEvent.ID), idpEvent = e.AppleIDPChangedEvent
// handler.NewCond(SAMLInstanceIDCol, idpEvent.Aggregate().InstanceID), default:
// }, return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YBez3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPChangedEventType /*, instance.AppleIDPChangedEventType*/})
// handler.WithTableSuffix(IDPTemplateSAMLSuffix), }
// ),
// )
// }
// return handler.NewMultiStatement( var orgId *string
// &idpEvent, if idpEvent.Aggregate().ResourceOwner != idpEvent.Agg.InstanceID {
// ops..., orgId = &idpEvent.Aggregate().ResourceOwner
// ), nil }
// }
// func (p *idpTemplateProjection) reduceAppleIDPAdded(event eventstore.Event) (*handler.Statement, error) { apple, err := p.idpRepo.GetApple(context.Background(), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
// var idpEvent idp.AppleIDPAddedEvent if err != nil {
// var idpOwnerType domain.IdentityProviderType return nil, err
// switch e := event.(type) { }
// case *org.AppleIDPAddedEvent:
// idpEvent = e.AppleIDPAddedEvent
// idpOwnerType = domain.IdentityProviderTypeOrg
// case *instance.AppleIDPAddedEvent:
// idpEvent = e.AppleIDPAddedEvent
// idpOwnerType = domain.IdentityProviderTypeSystem
// default:
// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-SFvg3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPAddedEventType /*, instance.AppleIDPAddedEventType*/})
// }
// return handler.NewMultiStatement( columns := make([]handler.Column, 0, 7)
// &idpEvent, reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges, &columns)
// handler.AddCreateStatement(
// []handler.Column{
// handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()),
// handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
// handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
// handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner),
// handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive),
// handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
// handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType),
// handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeApple),
// handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
// handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
// handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
// handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
// handler.NewCol(IDPTemplateAutoLinkingCol, idpEvent.AutoLinkingOption),
// },
// ),
// handler.AddCreateStatement(
// []handler.Column{
// handler.NewCol(AppleIDCol, idpEvent.ID),
// handler.NewCol(AppleInstanceIDCol, idpEvent.Aggregate().InstanceID),
// handler.NewCol(AppleClientIDCol, idpEvent.ClientID),
// handler.NewCol(AppleTeamIDCol, idpEvent.TeamID),
// handler.NewCol(AppleKeyIDCol, idpEvent.KeyID),
// handler.NewCol(ApplePrivateKeyCol, idpEvent.PrivateKey),
// handler.NewCol(AppleScopesCol, database.TextArray[string](idpEvent.Scopes)),
// },
// handler.WithTableSuffix(IDPTemplateAppleSuffix),
// ),
// ), nil
// }
// func (p *idpTemplateProjection) reduceAppleIDPChanged(event eventstore.Event) (*handler.Statement, error) { payload := &apple.Apple
// var idpEvent idp.AppleIDPChangedEvent payloadChanged := reduceAppleIDPRelationalChangedColumns(payload, &idpEvent)
// switch e := event.(type) { if payloadChanged {
// case *org.AppleIDPChangedEvent: payload, err := json.Marshal(payload)
// idpEvent = e.AppleIDPChangedEvent if err != nil {
// case *instance.AppleIDPChangedEvent: return nil, err
// idpEvent = e.AppleIDPChangedEvent }
// default: columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payload))
// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-GBez3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPChangedEventType /*, instance.AppleIDPChangedEventType*/}) }
// }
// ops := make([]func(eventstore.Event) handler.Exec, 0, 2) return handler.NewMultiStatement(
// ops = append(ops, &idpEvent,
// handler.AddUpdateStatement( handler.AddUpdateStatement(
// reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges), columns,
// []handler.Condition{ []handler.Condition{
// handler.NewCond(IDPTemplateIDCol, idpEvent.ID), handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// }, handler.NewCond(IDPRelationalOrgId, orgId),
// ), },
// ) ),
// appleCols := reduceAppleIDPChangedColumns(idpEvent) ), nil
// if len(appleCols) > 0 { }
// ops = append(ops,
// handler.AddUpdateStatement(
// appleCols,
// []handler.Condition{
// handler.NewCond(AppleIDCol, idpEvent.ID),
// handler.NewCond(AppleInstanceIDCol, idpEvent.Aggregate().InstanceID),
// },
// handler.WithTableSuffix(IDPTemplateAppleSuffix),
// ),
// )
// }
// return handler.NewMultiStatement( func (p *idpTemplateRelationalProjection) reduceSAMLIDPAdded(event eventstore.Event) (*handler.Statement, error) {
// &idpEvent, var idpEvent idp.SAMLIDPAddedEvent
// ops..., switch e := event.(type) {
// ), nil case *org.SAMLIDPAddedEvent:
// } idpEvent = e.SAMLIDPAddedEvent
case *instance.SAMLIDPAddedEvent:
idpEvent = e.SAMLIDPAddedEvent
default:
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Ys02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPAddedEventType, instance.SAMLIDPAddedEventType})
}
fmt.Printf("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> idpEvent.NameIDFormat = %+v\n", idpEvent.NameIDFormat)
saml := db_domain.SAML{
Metadata: idpEvent.Metadata,
Key: idpEvent.Key,
Certificate: idpEvent.Certificate,
Binding: idpEvent.Binding,
WithSignedRequest: idpEvent.WithSignedRequest,
NameIDFormat: idpEvent.NameIDFormat,
TransientMappingAttributeName: idpEvent.TransientMappingAttributeName,
FederatedLogoutEnabled: idpEvent.FederatedLogoutEnabled,
}
payload, err := json.Marshal(saml)
if err != nil {
return nil, err
}
var orgId *string
if idpEvent.Aggregate().ResourceOwner != idpEvent.Agg.InstanceID {
orgId = &idpEvent.Aggregate().ResourceOwner
}
return handler.NewMultiStatement(
&idpEvent,
handler.AddCreateStatement(
[]handler.Column{
handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
handler.NewCol(IDPRelationalOrgId, orgId),
handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
handler.NewCol(IDPTemplateTypeCol, db_domain.IDPTypeSAML.String()),
handler.NewCol(IDPTemplateStateCol, db_domain.IDPStateActive.String()),
handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
handler.NewCol(IDPRelationalAllowAutoLinkingCol, db_domain.IDPAutoLinkingOption(idpEvent.AutoLinkingOption).String()),
handler.NewCol(CreatedAt, idpEvent.CreationDate()),
handler.NewCol(IDPRelationalPayloadCol, payload),
},
),
), nil
}
func (p *idpTemplateRelationalProjection) reduceSAMLIDPChanged(event eventstore.Event) (*handler.Statement, error) {
var idpEvent idp.SAMLIDPChangedEvent
switch e := event.(type) {
case *org.SAMLIDPChangedEvent:
idpEvent = e.SAMLIDPChangedEvent
case *instance.SAMLIDPChangedEvent:
idpEvent = e.SAMLIDPChangedEvent
default:
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y7c0fii4ad", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPChangedEventType, instance.SAMLIDPChangedEventType})
}
var orgId *string
if idpEvent.Aggregate().ResourceOwner != idpEvent.Agg.InstanceID {
orgId = &idpEvent.Aggregate().ResourceOwner
}
saml, err := p.idpRepo.GetSAML(context.Background(), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
if err != nil {
return nil, err
}
columns := make([]handler.Column, 0, 7)
reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges, &columns)
payload := &saml.SAML
payloadChanged := reduceSAMLIDPRelationalChangedColumns(payload, &idpEvent)
if payloadChanged {
payload, err := json.Marshal(payload)
if err != nil {
return nil, err
}
columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payload))
}
return handler.NewMultiStatement(
&idpEvent,
handler.AddUpdateStatement(
columns,
[]handler.Condition{
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
handler.NewCond(IDPRelationalOrgId, orgId),
},
),
), nil
// ops := make([]func(eventstore.Event) handler.Exec, 0, 2)
// ops = append(ops,
// handler.AddUpdateStatement(
// reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges),
// []handler.Condition{
// handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// },
// ),
// )
// if len(SAMLCols) > 0 {
// ops = append(ops,
// handler.AddUpdateStatement(
// SAMLCols,
// []handler.Condition{
// handler.NewCond(SAMLIDCol, idpEvent.ID),
// handler.NewCond(SAMLInstanceIDCol, idpEvent.Aggregate().InstanceID),
// },
// handler.WithTableSuffix(IDPTemplateSAMLSuffix),
// ),
// )
// }
// return handler.NewMultiStatement(
// &idpEvent,
// ops...,
// ), nil
}
// func (p *idpTemplateProjection) reduceIDPConfigRemoved(event eventstore.Event) (*handler.Statement, error) { // func (p *idpTemplateProjection) reduceIDPConfigRemoved(event eventstore.Event) (*handler.Statement, error) {
// var idpEvent idpconfig.IDPConfigRemovedEvent // var idpEvent idpconfig.IDPConfigRemovedEvent
@@ -2072,25 +2114,25 @@ func (p *idpTemplateRelationalProjection) reduceLDAPIDPChanged(event eventstore.
// ), nil // ), nil
// } // }
// func (p *idpTemplateProjection) reduceIDPRemoved(event eventstore.Event) (*handler.Statement, error) { func (p *idpTemplateRelationalProjection) reduceIDPRemoved(event eventstore.Event) (*handler.Statement, error) {
// var idpEvent idp.RemovedEvent var idpEvent idp.RemovedEvent
// switch e := event.(type) { switch e := event.(type) {
// case *org.IDPRemovedEvent: case *org.IDPRemovedEvent:
// idpEvent = e.RemovedEvent idpEvent = e.RemovedEvent
// case *instance.IDPRemovedEvent: case *instance.IDPRemovedEvent:
// idpEvent = e.RemovedEvent idpEvent = e.RemovedEvent
// default: default:
// return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-xbcvwin2", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPRemovedEventType, instance.IDPRemovedEventType}) return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-xbcvwin2", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPRemovedEventType, instance.IDPRemovedEventType})
// } }
// return handler.NewDeleteStatement( return handler.NewDeleteStatement(
// &idpEvent, &idpEvent,
// []handler.Condition{ []handler.Condition{
// handler.NewCond(IDPTemplateIDCol, idpEvent.ID), handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
// handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID), handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
// }, },
// ), nil ), nil
// } }
// func (p *idpTemplateProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) { // func (p *idpTemplateProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) {
// e, ok := event.(*org.OrgRemovedEvent) // e, ok := event.(*org.OrgRemovedEvent)
@@ -2757,3 +2799,68 @@ func reduceLDAPIDPRelationalChangedColumns(payload *db_domain.LDAP, idpEvent *id
} }
return payloadChange return payloadChange
} }
func reduceAppleIDPRelationalChangedColumns(payload *domain.Apple, idpEvent *idp.AppleIDPChangedEvent) bool {
payloadChange := false
if idpEvent.ClientID != nil {
payloadChange = true
payload.ClientID = *idpEvent.ClientID
}
if idpEvent.TeamID != nil {
payloadChange = true
payload.TeamID = *idpEvent.TeamID
}
if idpEvent.KeyID != nil {
payloadChange = true
payload.KeyID = *idpEvent.KeyID
}
if idpEvent.PrivateKey != nil {
payloadChange = true
payload.PrivateKey = idpEvent.PrivateKey
}
if idpEvent.Scopes != nil {
payloadChange = true
payload.Scopes = idpEvent.Scopes
}
return payloadChange
}
func reduceSAMLIDPRelationalChangedColumns(payload *domain.SAML, idpEvent *idp.SAMLIDPChangedEvent) bool {
payloadChange := false
if idpEvent.Metadata != nil {
payloadChange = true
payload.Metadata = idpEvent.Metadata
fmt.Println("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> METTTADATA")
}
if idpEvent.Key != nil {
payloadChange = true
payload.Key = idpEvent.Key
fmt.Println("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> KEEEEEEEEEEEEEEY")
}
if idpEvent.Certificate != nil {
payloadChange = true
payload.Certificate = idpEvent.Certificate
}
if idpEvent.Binding != nil {
payloadChange = true
payload.Binding = *idpEvent.Binding
fmt.Println("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> BINDING")
}
if idpEvent.WithSignedRequest != nil {
payloadChange = true
payload.WithSignedRequest = *idpEvent.WithSignedRequest
}
if idpEvent.NameIDFormat != nil {
payloadChange = true
payload.NameIDFormat = idpEvent.NameIDFormat
}
if idpEvent.TransientMappingAttributeName != nil {
payloadChange = true
payload.TransientMappingAttributeName = *idpEvent.TransientMappingAttributeName
}
if idpEvent.FederatedLogoutEnabled != nil {
payloadChange = true
payload.FederatedLogoutEnabled = *idpEvent.FederatedLogoutEnabled
}
return payloadChange
}