diff --git a/backend/v3/domain/azuretenanttype_enumer.go b/backend/v3/domain/azuretenanttype_enumer.go
new file mode 100644
index 00000000000..0a083ba6d5c
--- /dev/null
+++ b/backend/v3/domain/azuretenanttype_enumer.go
@@ -0,0 +1,82 @@
+// Code generated by "enumer -type AzureTenantType -transform lower -trimprefix AzureTenantType"; DO NOT EDIT.
+
+package domain
+
+import (
+ "fmt"
+ "strings"
+)
+
+const _AzureTenantTypeName = "commonorganizationsconsumers"
+
+var _AzureTenantTypeIndex = [...]uint8{0, 6, 19, 28}
+
+const _AzureTenantTypeLowerName = "commonorganizationsconsumers"
+
+func (i AzureTenantType) String() string {
+ if i >= AzureTenantType(len(_AzureTenantTypeIndex)-1) {
+ return fmt.Sprintf("AzureTenantType(%d)", i)
+ }
+ return _AzureTenantTypeName[_AzureTenantTypeIndex[i]:_AzureTenantTypeIndex[i+1]]
+}
+
+// An "invalid array index" compiler error signifies that the constant values have changed.
+// Re-run the stringer command to generate them again.
+func _AzureTenantTypeNoOp() {
+ var x [1]struct{}
+ _ = x[AzureTenantTypeCommon-(0)]
+ _ = x[AzureTenantTypeOrganizations-(1)]
+ _ = x[AzureTenantTypeConsumers-(2)]
+}
+
+var _AzureTenantTypeValues = []AzureTenantType{AzureTenantTypeCommon, AzureTenantTypeOrganizations, AzureTenantTypeConsumers}
+
+var _AzureTenantTypeNameToValueMap = map[string]AzureTenantType{
+ _AzureTenantTypeName[0:6]: AzureTenantTypeCommon,
+ _AzureTenantTypeLowerName[0:6]: AzureTenantTypeCommon,
+ _AzureTenantTypeName[6:19]: AzureTenantTypeOrganizations,
+ _AzureTenantTypeLowerName[6:19]: AzureTenantTypeOrganizations,
+ _AzureTenantTypeName[19:28]: AzureTenantTypeConsumers,
+ _AzureTenantTypeLowerName[19:28]: AzureTenantTypeConsumers,
+}
+
+var _AzureTenantTypeNames = []string{
+ _AzureTenantTypeName[0:6],
+ _AzureTenantTypeName[6:19],
+ _AzureTenantTypeName[19:28],
+}
+
+// AzureTenantTypeString retrieves an enum value from the enum constants string name.
+// Throws an error if the param is not part of the enum.
+func AzureTenantTypeString(s string) (AzureTenantType, error) {
+ if val, ok := _AzureTenantTypeNameToValueMap[s]; ok {
+ return val, nil
+ }
+
+ if val, ok := _AzureTenantTypeNameToValueMap[strings.ToLower(s)]; ok {
+ return val, nil
+ }
+ return 0, fmt.Errorf("%s does not belong to AzureTenantType values", s)
+}
+
+// AzureTenantTypeValues returns all values of the enum
+func AzureTenantTypeValues() []AzureTenantType {
+ return _AzureTenantTypeValues
+}
+
+// AzureTenantTypeStrings returns a slice of all String values of the enum
+func AzureTenantTypeStrings() []string {
+ strs := make([]string, len(_AzureTenantTypeNames))
+ copy(strs, _AzureTenantTypeNames)
+ return strs
+}
+
+// IsAAzureTenantType returns "true" if the value is listed in the enum definition. "false" otherwise
+func (i AzureTenantType) IsAAzureTenantType() bool {
+ for _, v := range _AzureTenantTypeValues {
+ if i == v {
+ return true
+ }
+ }
+ return false
+}
diff --git a/backend/v3/domain/errors.go b/backend/v3/domain/errors.go
index a11c31c07d4..cb1a192c82f 100644
--- a/backend/v3/domain/errors.go
+++ b/backend/v3/domain/errors.go
@@ -1,7 +1,29 @@
package domain
-import "errors"
-
-var (
- ErrNoAdminSpecified = errors.New("at least one admin must be specified")
+import (
+ "errors"
+ "fmt"
)
+
+var ErrNoAdminSpecified = errors.New("at least one admin must be specified")
+
+type wrongIDPTypeError struct {
+ expected IDPType
+ got string
+}
+
+func NewIDPWrongTypeError(expected IDPType, got fmt.Stringer) error {
+ return &wrongIDPTypeError{
+ expected: expected,
+ got: got.String(),
+ }
+}
+
+func (e *wrongIDPTypeError) Error() string {
+ return fmt.Sprintf("wrong idp type returned, expected: %v, got: %v", e.expected, e.got)
+}
+
+func (e *wrongIDPTypeError) Is(target error) bool {
+ _, ok := target.(*wrongIDPTypeError)
+ return ok
+}
diff --git a/backend/v3/domain/id_provider.go b/backend/v3/domain/id_provider.go
new file mode 100644
index 00000000000..6f2bab1e3a1
--- /dev/null
+++ b/backend/v3/domain/id_provider.go
@@ -0,0 +1,355 @@
+package domain
+
+import (
+ "context"
+ "encoding/json"
+ "time"
+
+ "github.com/zitadel/zitadel/backend/v3/storage/database"
+ "github.com/zitadel/zitadel/internal/crypto"
+ "github.com/zitadel/zitadel/internal/domain"
+)
+
+//go:generate enumer -type IDPType -transform lower -trimprefix IDPType
+type IDPType uint8
+
+const (
+ IDPTypeOIDC IDPType = iota + 1
+ IDPTypeJWT
+ IDPTypeOAuth
+ IDPTypeSAML
+ IDPTypeLDAP
+ IDPTypeGitHub
+ IDPTypeGitHubEnterprise
+ IDPTypeGitLab
+ IDPTypeGitLabSelfHosted
+ IDPTypeAzure
+ IDPTypeGoogle
+ IDPTypeApple
+)
+
+//go:generate enumer -type IDPState -transform lower -trimprefix IDPState -sql
+type IDPState uint8
+
+const (
+ IDPStateActive IDPState = iota
+ IDPStateInactive
+)
+
+//go:generate enumer -type IDPAutoLinkingField -transform lower -trimprefix IDPAutoLinkingField
+type IDPAutoLinkingField uint8
+
+const (
+ IDPAutoLinkingFieldUserName IDPAutoLinkingField = iota + 1
+ IDPAutoLinkingFieldEmail
+)
+
+type OIDCMappingField int8
+
+const (
+ OIDCMappingFieldUnspecified OIDCMappingField = iota
+ OIDCMappingFieldPreferredLoginName
+ OIDCMappingFieldEmail
+ // count is for validation purposes
+ //nolint: unused
+ oidcMappingFieldCount
+)
+
+type IdentityProvider struct {
+ InstanceID string `json:"instanceId,omitempty" db:"instance_id"`
+ OrgID *string `json:"orgId,omitempty" db:"org_id"`
+ ID string `json:"id,omitempty" db:"id"`
+ State IDPState `json:"state,omitempty" db:"state"`
+ Name string `json:"name,omitempty" db:"name"`
+ // Type represents the type of and idp. It is a pointer because it can be nil during the migration of the events
+ Type *IDPType `json:"type,omitempty" db:"type"`
+ AllowCreation bool `json:"allowCreation,omitempty" db:"allow_creation"`
+ AutoRegister bool `json:"autoRegister,omitempty" db:"auto_register"`
+ AllowAutoCreation bool `json:"allowAutoCreation,omitempty" db:"allow_auto_creation"`
+ AllowAutoUpdate bool `json:"allowAutoUpdate,omitempty" db:"allow_auto_update"`
+ AllowLinking bool `json:"allowLinking,omitempty" db:"allow_linking"`
+ AutoLinkingField *IDPAutoLinkingField `json:"autoLinkingField,omitempty" db:"auto_linking_field"`
+ StylingType *int16 `json:"stylingType,omitempty" db:"styling_type"`
+ Payload json.RawMessage `json:"payload,omitempty" db:"payload"`
+ CreatedAt time.Time `json:"createdAt,omitzero" db:"created_at"`
+ UpdatedAt time.Time `json:"updatedAt,omitzero" db:"updated_at"`
+}
+
+type OIDC struct {
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ Issuer string `json:"issuer,omitempty"`
+ AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
+ TokenEndpoint string `json:"tokenEndpoint,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+ IDPDisplayNameMapping OIDCMappingField `json:"IDPDisplayNameMapping,omitempty"`
+ UserNameMapping OIDCMappingField `json:"usernameMapping,omitempty"`
+ IsIDTokenMapping bool `json:"idTokenMapping,omitempty"`
+ UsePKCE bool `json:"usePKCE,omitempty"`
+}
+
+type IDPOIDC struct {
+ *IdentityProvider
+ OIDC
+}
+
+type JWT struct {
+ IDPConfigID string `json:"idpConfigId"`
+ JWTEndpoint string `json:"jwtEndpoint,omitempty"`
+ Issuer string `json:"issuer,omitempty"`
+ KeysEndpoint string `json:"keysEndpoint,omitempty"`
+ HeaderName string `json:"headerName,omitempty"`
+}
+
+type IDPJWT struct {
+ *IdentityProvider
+ JWT
+}
+
+type OAuth struct {
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
+ TokenEndpoint string `json:"tokenEndpoint,omitempty"`
+ UserEndpoint string `json:"userEndpoint,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+ IDAttribute string `json:"idAttribute,omitempty"`
+ UsePKCE bool `json:"usePKCE,omitempty"`
+}
+
+type IDPOAuth struct {
+ *IdentityProvider
+ OAuth
+}
+
+//go:generate enumer -type AzureTenantType -transform lower -trimprefix AzureTenantType
+type AzureTenantType uint8
+
+const (
+ AzureTenantTypeCommon AzureTenantType = iota
+ AzureTenantTypeOrganizations
+ AzureTenantTypeConsumers
+)
+
+type Azure struct {
+ ClientID string `json:"client_id,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"client_secret,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+ Tenant AzureTenantType `json:"tenant,omitempty"`
+ IsEmailVerified bool `json:"isEmailVerified,omitempty"`
+}
+
+type IDPAzureAD struct {
+ *IdentityProvider
+ Azure
+}
+
+type Google struct {
+ ClientID string `json:"clientId"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type IDPGoogle struct {
+ *IdentityProvider
+ Google
+}
+
+type Github struct {
+ ClientID string `json:"clientId"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type IDPGithub struct {
+ *IdentityProvider
+ Github
+}
+
+type GithubEnterprise struct {
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ AuthorizationEndpoint string `json:"authorizationEndpoint,omitempty"`
+ TokenEndpoint string `json:"tokenEndpoint,omitempty"`
+ UserEndpoint string `json:"userEndpoint,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type IDPGithubEnterprise struct {
+ *IdentityProvider
+ GithubEnterprise
+}
+
+type Gitlab struct {
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type IDPGitlab struct {
+ *IdentityProvider
+ Gitlab
+}
+
+type GitlabSelfHosting struct {
+ Issuer string `json:"issuer"`
+ ClientID string `json:"clientId,omitempty"`
+ ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type IDPGitlabSelfHosting struct {
+ *IdentityProvider
+ GitlabSelfHosting
+}
+
+type LDAP struct {
+ Servers []string `json:"servers"`
+ StartTLS bool `json:"startTLS"`
+ BaseDN string `json:"baseDN"`
+ BindDN string `json:"bindDN"`
+ BindPassword *crypto.CryptoValue `json:"bindPassword"`
+ UserBase string `json:"userBase"`
+ UserObjectClasses []string `json:"userObjectClasses"`
+ UserFilters []string `json:"userFilters"`
+ Timeout time.Duration `json:"timeout"`
+ RootCA []byte `json:"rootCA"`
+
+ LDAPAttributes
+}
+
+type LDAPAttributes struct {
+ IDAttribute string `json:"idAttribute,omitempty"`
+ FirstNameAttribute string `json:"firstNameAttribute,omitempty"`
+ LastNameAttribute string `json:"lastNameAttribute,omitempty"`
+ DisplayNameAttribute string `json:"displayNameAttribute,omitempty"`
+ NickNameAttribute string `json:"nickNameAttribute,omitempty"`
+ PreferredUsernameAttribute string `json:"preferredUsernameAttribute,omitempty"`
+ EmailAttribute string `json:"emailAttribute,omitempty"`
+ EmailVerifiedAttribute string `json:"emailVerifiedAttribute,omitempty"`
+ PhoneAttribute string `json:"phoneAttribute,omitempty"`
+ PhoneVerifiedAttribute string `json:"phoneVerifiedAttribute,omitempty"`
+ PreferredLanguageAttribute string `json:"preferredLanguageAttribute,omitempty"`
+ AvatarURLAttribute string `json:"avatarURLAttribute,omitempty"`
+ ProfileAttribute string `json:"profileAttribute,omitempty"`
+}
+
+type IDPLDAP struct {
+ *IdentityProvider
+ 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"`
+ SignatureAlgorithm string `json:"signatureAlgorithm,omitempty"`
+}
+
+type IDPSAML struct {
+ *IdentityProvider
+ SAML
+}
+
+// IDPIdentifierCondition is used to help specify a single identity_provider,
+// 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)
+type IDPIdentifierCondition interface {
+ database.Condition
+}
+
+type idProviderColumns interface {
+ InstanceIDColumn() database.Column
+ OrgIDColumn() database.Column
+ IDColumn() database.Column
+ StateColumn() database.Column
+ NameColumn() database.Column
+ TypeColumn() database.Column
+ AllowCreationColumn() database.Column
+ AutoRegisterColumn() database.Column
+ AllowAutoCreationColumn() database.Column
+ AllowAutoUpdateColumn() database.Column
+ AllowLinkingColumn() database.Column
+ AllowAutoLinkingColumn() database.Column
+ StylingTypeColumn() database.Column
+ PayloadColumn() database.Column
+ CreatedAtColumn() database.Column
+ UpdatedAtColumn() database.Column
+}
+
+type idProviderConditions interface {
+ InstanceIDCondition(id string) database.Condition
+ OrgIDCondition(id *string) database.Condition
+ IDCondition(id string) IDPIdentifierCondition
+ StateCondition(state IDPState) database.Condition
+ NameCondition(name string) IDPIdentifierCondition
+ TypeCondition(typee IDPType) database.Condition
+ AutoRegisterCondition(allow bool) database.Condition
+ AllowCreationCondition(allow bool) database.Condition
+ AllowAutoCreationCondition(allow bool) database.Condition
+ AllowAutoUpdateCondition(allow bool) database.Condition
+ AllowLinkingCondition(allow bool) database.Condition
+ AllowAutoLinkingCondition(linkingType IDPAutoLinkingField) database.Condition
+ StylingTypeCondition(style int16) database.Condition
+ PayloadCondition(payload string) database.Condition
+}
+
+type idProviderChanges interface {
+ SetName(name string) database.Change
+ SetState(state IDPState) database.Change
+ SetAllowCreation(allow bool) database.Change
+ SetAutoRegister(allow bool) database.Change
+ SetAllowAutoCreation(allow bool) database.Change
+ SetAllowAutoUpdate(allow bool) database.Change
+ SetAllowLinking(allow bool) database.Change
+ SetAutoAllowLinking(allow bool) database.Change
+ SetStylingType(stylingType int16) database.Change
+ SetPayload(payload string) database.Change
+ SetUpdatedAt(createdAt *time.Time) database.Change
+}
+
+type IDProviderRepository interface {
+ idProviderColumns
+ idProviderConditions
+ idProviderChanges
+
+ Get(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IdentityProvider, error)
+ List(ctx context.Context, client database.QueryExecutor, conditions ...database.Condition) ([]*IdentityProvider, error)
+
+ Create(ctx context.Context, client database.QueryExecutor, idp *IdentityProvider) error
+ Update(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string, changes ...database.Change) (int64, error)
+ Delete(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (int64, error)
+
+ GetOIDC(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPOIDC, error)
+ GetJWT(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPJWT, error)
+
+ GetOAuth(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPOAuth, error)
+
+ GetAzureAD(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPAzureAD, error)
+ GetGoogle(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGoogle, error)
+ GetGithub(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGithub, error)
+ GetGithubEnterprise(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGithubEnterprise, error)
+ GetGitlab(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlab, error)
+ GetGitlabSelfHosting(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPGitlabSelfHosting, error)
+ GetLDAP(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPLDAP, error)
+ GetApple(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPApple, error)
+ GetSAML(ctx context.Context, client database.QueryExecutor, id IDPIdentifierCondition, instanceID string, orgID *string) (*IDPSAML, error)
+}
diff --git a/backend/v3/domain/idpautolinkingfield_enumer.go b/backend/v3/domain/idpautolinkingfield_enumer.go
new file mode 100644
index 00000000000..037c471ebe4
--- /dev/null
+++ b/backend/v3/domain/idpautolinkingfield_enumer.go
@@ -0,0 +1,79 @@
+// Code generated by "enumer -type IDPAutoLinkingField -transform lower -trimprefix IDPAutoLinkingField"; DO NOT EDIT.
+
+package domain
+
+import (
+ "fmt"
+ "strings"
+)
+
+const _IDPAutoLinkingFieldName = "usernameemail"
+
+var _IDPAutoLinkingFieldIndex = [...]uint8{0, 8, 13}
+
+const _IDPAutoLinkingFieldLowerName = "usernameemail"
+
+func (i IDPAutoLinkingField) String() string {
+ i -= 1
+ if i >= IDPAutoLinkingField(len(_IDPAutoLinkingFieldIndex)-1) {
+ return fmt.Sprintf("IDPAutoLinkingField(%d)", i+1)
+ }
+ return _IDPAutoLinkingFieldName[_IDPAutoLinkingFieldIndex[i]:_IDPAutoLinkingFieldIndex[i+1]]
+}
+
+// An "invalid array index" compiler error signifies that the constant values have changed.
+// Re-run the stringer command to generate them again.
+func _IDPAutoLinkingFieldNoOp() {
+ var x [1]struct{}
+ _ = x[IDPAutoLinkingFieldUserName-(1)]
+ _ = x[IDPAutoLinkingFieldEmail-(2)]
+}
+
+var _IDPAutoLinkingFieldValues = []IDPAutoLinkingField{IDPAutoLinkingFieldUserName, IDPAutoLinkingFieldEmail}
+
+var _IDPAutoLinkingFieldNameToValueMap = map[string]IDPAutoLinkingField{
+ _IDPAutoLinkingFieldName[0:8]: IDPAutoLinkingFieldUserName,
+ _IDPAutoLinkingFieldLowerName[0:8]: IDPAutoLinkingFieldUserName,
+ _IDPAutoLinkingFieldName[8:13]: IDPAutoLinkingFieldEmail,
+ _IDPAutoLinkingFieldLowerName[8:13]: IDPAutoLinkingFieldEmail,
+}
+
+var _IDPAutoLinkingFieldNames = []string{
+ _IDPAutoLinkingFieldName[0:8],
+ _IDPAutoLinkingFieldName[8:13],
+}
+
+// IDPAutoLinkingFieldString retrieves an enum value from the enum constants string name.
+// Throws an error if the param is not part of the enum.
+func IDPAutoLinkingFieldString(s string) (IDPAutoLinkingField, error) {
+ if val, ok := _IDPAutoLinkingFieldNameToValueMap[s]; ok {
+ return val, nil
+ }
+
+ if val, ok := _IDPAutoLinkingFieldNameToValueMap[strings.ToLower(s)]; ok {
+ return val, nil
+ }
+ return 0, fmt.Errorf("%s does not belong to IDPAutoLinkingField values", s)
+}
+
+// IDPAutoLinkingFieldValues returns all values of the enum
+func IDPAutoLinkingFieldValues() []IDPAutoLinkingField {
+ return _IDPAutoLinkingFieldValues
+}
+
+// IDPAutoLinkingFieldStrings returns a slice of all String values of the enum
+func IDPAutoLinkingFieldStrings() []string {
+ strs := make([]string, len(_IDPAutoLinkingFieldNames))
+ copy(strs, _IDPAutoLinkingFieldNames)
+ return strs
+}
+
+// IsAIDPAutoLinkingField returns "true" if the value is listed in the enum definition. "false" otherwise
+func (i IDPAutoLinkingField) IsAIDPAutoLinkingField() bool {
+ for _, v := range _IDPAutoLinkingFieldValues {
+ if i == v {
+ return true
+ }
+ }
+ return false
+}
diff --git a/backend/v3/domain/idpstate_enumer.go b/backend/v3/domain/idpstate_enumer.go
new file mode 100644
index 00000000000..1b063363eac
--- /dev/null
+++ b/backend/v3/domain/idpstate_enumer.go
@@ -0,0 +1,109 @@
+// Code generated by "enumer -type IDPState -transform lower -trimprefix IDPState -sql"; DO NOT EDIT.
+
+package domain
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "strings"
+)
+
+const _IDPStateName = "activeinactive"
+
+var _IDPStateIndex = [...]uint8{0, 6, 14}
+
+const _IDPStateLowerName = "activeinactive"
+
+func (i IDPState) String() string {
+ if i >= IDPState(len(_IDPStateIndex)-1) {
+ return fmt.Sprintf("IDPState(%d)", i)
+ }
+ return _IDPStateName[_IDPStateIndex[i]:_IDPStateIndex[i+1]]
+}
+
+// An "invalid array index" compiler error signifies that the constant values have changed.
+// Re-run the stringer command to generate them again.
+func _IDPStateNoOp() {
+ var x [1]struct{}
+ _ = x[IDPStateActive-(0)]
+ _ = x[IDPStateInactive-(1)]
+}
+
+var _IDPStateValues = []IDPState{IDPStateActive, IDPStateInactive}
+
+var _IDPStateNameToValueMap = map[string]IDPState{
+ _IDPStateName[0:6]: IDPStateActive,
+ _IDPStateLowerName[0:6]: IDPStateActive,
+ _IDPStateName[6:14]: IDPStateInactive,
+ _IDPStateLowerName[6:14]: IDPStateInactive,
+}
+
+var _IDPStateNames = []string{
+ _IDPStateName[0:6],
+ _IDPStateName[6:14],
+}
+
+// IDPStateString retrieves an enum value from the enum constants string name.
+// Throws an error if the param is not part of the enum.
+func IDPStateString(s string) (IDPState, error) {
+ if val, ok := _IDPStateNameToValueMap[s]; ok {
+ return val, nil
+ }
+
+ if val, ok := _IDPStateNameToValueMap[strings.ToLower(s)]; ok {
+ return val, nil
+ }
+ return 0, fmt.Errorf("%s does not belong to IDPState values", s)
+}
+
+// IDPStateValues returns all values of the enum
+func IDPStateValues() []IDPState {
+ return _IDPStateValues
+}
+
+// IDPStateStrings returns a slice of all String values of the enum
+func IDPStateStrings() []string {
+ strs := make([]string, len(_IDPStateNames))
+ copy(strs, _IDPStateNames)
+ return strs
+}
+
+// IsAIDPState returns "true" if the value is listed in the enum definition. "false" otherwise
+func (i IDPState) IsAIDPState() bool {
+ for _, v := range _IDPStateValues {
+ if i == v {
+ return true
+ }
+ }
+ return false
+}
+
+func (i IDPState) Value() (driver.Value, error) {
+ return i.String(), nil
+}
+
+func (i *IDPState) Scan(value interface{}) error {
+ if value == nil {
+ return nil
+ }
+
+ var str string
+ switch v := value.(type) {
+ case []byte:
+ str = string(v)
+ case string:
+ str = v
+ case fmt.Stringer:
+ str = v.String()
+ default:
+ return fmt.Errorf("invalid value of IDPState: %[1]T(%[1]v)", value)
+ }
+
+ val, err := IDPStateString(str)
+ if err != nil {
+ return err
+ }
+
+ *i = val
+ return nil
+}
diff --git a/backend/v3/domain/idptype_enumer.go b/backend/v3/domain/idptype_enumer.go
new file mode 100644
index 00000000000..f5e895ba714
--- /dev/null
+++ b/backend/v3/domain/idptype_enumer.go
@@ -0,0 +1,119 @@
+// Code generated by "enumer -type IDPType -transform lower -trimprefix IDPType"; DO NOT EDIT.
+
+package domain
+
+import (
+ "fmt"
+ "strings"
+)
+
+const _IDPTypeName = "oidcjwtoauthsamlldapgithubgithubenterprisegitlabgitlabselfhostedazuregoogleapple"
+
+var _IDPTypeIndex = [...]uint8{0, 4, 7, 12, 16, 20, 26, 42, 48, 64, 69, 75, 80}
+
+const _IDPTypeLowerName = "oidcjwtoauthsamlldapgithubgithubenterprisegitlabgitlabselfhostedazuregoogleapple"
+
+func (i IDPType) String() string {
+ i -= 1
+ if i >= IDPType(len(_IDPTypeIndex)-1) {
+ return fmt.Sprintf("IDPType(%d)", i+1)
+ }
+ return _IDPTypeName[_IDPTypeIndex[i]:_IDPTypeIndex[i+1]]
+}
+
+// An "invalid array index" compiler error signifies that the constant values have changed.
+// Re-run the stringer command to generate them again.
+func _IDPTypeNoOp() {
+ var x [1]struct{}
+ _ = x[IDPTypeOIDC-(1)]
+ _ = x[IDPTypeJWT-(2)]
+ _ = x[IDPTypeOAuth-(3)]
+ _ = x[IDPTypeSAML-(4)]
+ _ = x[IDPTypeLDAP-(5)]
+ _ = x[IDPTypeGitHub-(6)]
+ _ = x[IDPTypeGitHubEnterprise-(7)]
+ _ = x[IDPTypeGitLab-(8)]
+ _ = x[IDPTypeGitLabSelfHosted-(9)]
+ _ = x[IDPTypeAzure-(10)]
+ _ = x[IDPTypeGoogle-(11)]
+ _ = x[IDPTypeApple-(12)]
+}
+
+var _IDPTypeValues = []IDPType{IDPTypeOIDC, IDPTypeJWT, IDPTypeOAuth, IDPTypeSAML, IDPTypeLDAP, IDPTypeGitHub, IDPTypeGitHubEnterprise, IDPTypeGitLab, IDPTypeGitLabSelfHosted, IDPTypeAzure, IDPTypeGoogle, IDPTypeApple}
+
+var _IDPTypeNameToValueMap = map[string]IDPType{
+ _IDPTypeName[0:4]: IDPTypeOIDC,
+ _IDPTypeLowerName[0:4]: IDPTypeOIDC,
+ _IDPTypeName[4:7]: IDPTypeJWT,
+ _IDPTypeLowerName[4:7]: IDPTypeJWT,
+ _IDPTypeName[7:12]: IDPTypeOAuth,
+ _IDPTypeLowerName[7:12]: IDPTypeOAuth,
+ _IDPTypeName[12:16]: IDPTypeSAML,
+ _IDPTypeLowerName[12:16]: IDPTypeSAML,
+ _IDPTypeName[16:20]: IDPTypeLDAP,
+ _IDPTypeLowerName[16:20]: IDPTypeLDAP,
+ _IDPTypeName[20:26]: IDPTypeGitHub,
+ _IDPTypeLowerName[20:26]: IDPTypeGitHub,
+ _IDPTypeName[26:42]: IDPTypeGitHubEnterprise,
+ _IDPTypeLowerName[26:42]: IDPTypeGitHubEnterprise,
+ _IDPTypeName[42:48]: IDPTypeGitLab,
+ _IDPTypeLowerName[42:48]: IDPTypeGitLab,
+ _IDPTypeName[48:64]: IDPTypeGitLabSelfHosted,
+ _IDPTypeLowerName[48:64]: IDPTypeGitLabSelfHosted,
+ _IDPTypeName[64:69]: IDPTypeAzure,
+ _IDPTypeLowerName[64:69]: IDPTypeAzure,
+ _IDPTypeName[69:75]: IDPTypeGoogle,
+ _IDPTypeLowerName[69:75]: IDPTypeGoogle,
+ _IDPTypeName[75:80]: IDPTypeApple,
+ _IDPTypeLowerName[75:80]: IDPTypeApple,
+}
+
+var _IDPTypeNames = []string{
+ _IDPTypeName[0:4],
+ _IDPTypeName[4:7],
+ _IDPTypeName[7:12],
+ _IDPTypeName[12:16],
+ _IDPTypeName[16:20],
+ _IDPTypeName[20:26],
+ _IDPTypeName[26:42],
+ _IDPTypeName[42:48],
+ _IDPTypeName[48:64],
+ _IDPTypeName[64:69],
+ _IDPTypeName[69:75],
+ _IDPTypeName[75:80],
+}
+
+// IDPTypeString retrieves an enum value from the enum constants string name.
+// Throws an error if the param is not part of the enum.
+func IDPTypeString(s string) (IDPType, error) {
+ if val, ok := _IDPTypeNameToValueMap[s]; ok {
+ return val, nil
+ }
+
+ if val, ok := _IDPTypeNameToValueMap[strings.ToLower(s)]; ok {
+ return val, nil
+ }
+ return 0, fmt.Errorf("%s does not belong to IDPType values", s)
+}
+
+// IDPTypeValues returns all values of the enum
+func IDPTypeValues() []IDPType {
+ return _IDPTypeValues
+}
+
+// IDPTypeStrings returns a slice of all String values of the enum
+func IDPTypeStrings() []string {
+ strs := make([]string, len(_IDPTypeNames))
+ copy(strs, _IDPTypeNames)
+ return strs
+}
+
+// IsAIDPType returns "true" if the value is listed in the enum definition. "false" otherwise
+func (i IDPType) IsAIDPType() bool {
+ for _, v := range _IDPTypeValues {
+ if i == v {
+ return true
+ }
+ }
+ return false
+}
diff --git a/backend/v3/domain/organization.go b/backend/v3/domain/organization.go
index 32d6528ba86..da5407afdd5 100644
--- a/backend/v3/domain/organization.go
+++ b/backend/v3/domain/organization.go
@@ -32,7 +32,7 @@ type organizationColumns interface {
IDColumn() database.Column
// NameColumn returns the column for the name field.
NameColumn() database.Column
- // InstanceIDColumn returns the column for the default org id field
+ // InstanceIDColumn returns the column for the instance id field
InstanceIDColumn() database.Column
// StateColumn returns the column for the name field.
StateColumn() database.Column
diff --git a/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table.go b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table.go
new file mode 100644
index 00000000000..36bbe8e31c1
--- /dev/null
+++ b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table.go
@@ -0,0 +1,16 @@
+package migration
+
+import (
+ _ "embed"
+)
+
+var (
+ //go:embed 005_identity_providers_table/up.sql
+ up005IdentityProvidersTable string
+ //go:embed 005_identity_providers_table/down.sql
+ down005IdentityProvidersTable string
+)
+
+func init() {
+ registerSQLMigration(5, up005IdentityProvidersTable, down005IdentityProvidersTable)
+}
diff --git a/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/down.sql b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/down.sql
new file mode 100644
index 00000000000..e19e92fad0f
--- /dev/null
+++ b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/down.sql
@@ -0,0 +1,2 @@
+DROP TABLE zitadel.identity_providers;
+DROP TYPE zitadel.idp_state;
diff --git a/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/up.sql b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/up.sql
new file mode 100644
index 00000000000..760efeeb251
--- /dev/null
+++ b/backend/v3/storage/database/dialect/postgres/migration/005_identity_providers_table/up.sql
@@ -0,0 +1,44 @@
+CREATE TYPE zitadel.idp_state AS ENUM (
+ 'active',
+ 'inactive'
+);
+
+CREATE TABLE zitadel.identity_providers (
+ instance_id TEXT NOT NULL
+ , org_id TEXT
+ , id TEXT NOT NULL CHECK (id <> '')
+ , state zitadel.idp_state NOT NULL DEFAULT 'active'
+ , name TEXT NOT NULL CHECK (name <> '')
+ , type SMALLINT DEFAULT NULL
+ , auto_register BOOLEAN NOT NULL DEFAULT TRUE
+ , allow_creation BOOLEAN NOT NULL DEFAULT TRUE
+ , allow_auto_creation BOOLEAN NOT NULL DEFAULT TRUE
+ , allow_auto_update BOOLEAN NOT NULL DEFAULT TRUE
+ , allow_linking BOOLEAN NOT NULL DEFAULT TRUE
+ , auto_linking_field SMALLINT DEFAULT NULL
+ , styling_type SMALLINT
+ , payload JSONB
+
+ , created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+ , updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
+
+ , PRIMARY KEY (instance_id, id)
+ , CONSTRAINT identity_providers_id_unique UNIQUE NULLS NOT DISTINCT (instance_id, org_id, id)
+ , CONSTRAINT identity_providers_name_unique UNIQUE NULLS NOT DISTINCT (instance_id, org_id, name)
+ , FOREIGN KEY (instance_id) REFERENCES zitadel.instances(id)
+ , FOREIGN KEY (instance_id, org_id) REFERENCES zitadel.organizations(instance_id, id)
+);
+
+-- CREATE INDEX idx_identity_providers_org_id ON identity_providers(instance_id, org_id) WHERE org_id IS NOT NULL;
+CREATE INDEX idx_identity_providers_state ON zitadel.identity_providers(instance_id, state);
+CREATE INDEX idx_identity_providers_type ON zitadel.identity_providers(instance_id, type);
+-- CREATE INDEX idx_identity_providers_created_at ON identity_providers(created_at);
+-- CREATE INDEX idx_identity_providers_deleted_at ON identity_providers(deleted_at) WHERE deleted_at IS NOT NULL;
+
+
+CREATE TRIGGER trigger_set_updated_at
+BEFORE UPDATE ON zitadel.identity_providers
+FOR EACH ROW
+WHEN (NEW.updated_at IS NULL)
+EXECUTE FUNCTION zitadel.set_updated_at();
+
diff --git a/backend/v3/storage/database/events_testing/events_test.go b/backend/v3/storage/database/events_testing/events_test.go
index f2427ba4b59..cf279b897df 100644
--- a/backend/v3/storage/database/events_testing/events_test.go
+++ b/backend/v3/storage/database/events_testing/events_test.go
@@ -15,7 +15,9 @@ import (
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/dialect/postgres"
"github.com/zitadel/zitadel/internal/integration"
+ "github.com/zitadel/zitadel/pkg/grpc/admin"
v2beta "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta"
+ mgmt "github.com/zitadel/zitadel/pkg/grpc/management"
v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/system"
)
@@ -25,9 +27,12 @@ const ConnString = "host=localhost port=5432 user=zitadel password=zitadel dbnam
var (
dbPool *pgxpool.Pool
CTX context.Context
+ IAMCTX context.Context
Instance *integration.Instance
SystemClient system.SystemServiceClient
OrgClient v2beta_org.OrganizationServiceClient
+ AdminClient admin.AdminServiceClient
+ MgmtClient mgmt.ManagementServiceClient
)
var pool database.Pool
@@ -40,8 +45,11 @@ func TestMain(m *testing.M) {
CTX = integration.WithSystemAuthorization(ctx)
Instance = integration.NewInstance(CTX)
+ IAMCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
SystemClient = integration.SystemClient()
OrgClient = Instance.Client.OrgV2beta
+ AdminClient = Instance.Client.Admin
+ MgmtClient = Instance.Client.Mgmt
defer func() {
_, err := Instance.Client.InstanceV2Beta.DeleteInstance(CTX, &v2beta.DeleteInstanceRequest{
diff --git a/backend/v3/storage/database/events_testing/id_provider_instance_test.go b/backend/v3/storage/database/events_testing/id_provider_instance_test.go
new file mode 100644
index 00000000000..43060add66f
--- /dev/null
+++ b/backend/v3/storage/database/events_testing/id_provider_instance_test.go
@@ -0,0 +1,2530 @@
+//go:build integration
+
+package events_test
+
+import (
+ "testing"
+ "time"
+
+ "github.com/brianvoe/gofakeit/v6"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+
+ "github.com/zitadel/zitadel/backend/v3/domain"
+ "github.com/zitadel/zitadel/backend/v3/storage/database"
+ "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/pkg/grpc/admin"
+ "github.com/zitadel/zitadel/pkg/grpc/idp"
+ idp_grpc "github.com/zitadel/zitadel/pkg/grpc/idp"
+)
+
+var validSAMLMetadata1 = []byte(`
+
+
+
+
+
+
+
+
+
+
+
+ Tyw4csdpNNq0E7wi5FXWdVNkdPNg+cM6kK21VB2+iF0=
+
+
+ hWQSYmnBJENy/okk2qRDuHaZiyqpDsdV6BF9/T/LNjUh/8z4dV2NEZvkNhFEyQ+bqdj+NmRWvKqpg1dtgNJxQc32+IsLQvXNYyhMCtyG570/jaTOtm8daV4NKJyTV7SdwM6yfXgubz5YCRTyV13W2gBIFYppIRImIv5NDcjz+lEmWhnrkw8G2wRSFUY7VvkDn9rgsTzw/Pnsw6hlzpjGDYPMPx3ux3kjFVevdhFGNo+VC7t9ozruuGyH3yue9Re6FZoqa4oyWaPSOwei0ZH6UNqkX93Eo5Y49QKwaO8Rm+kWsOhdTqebVmCc+SpWbbrZbQj4nSLgWGlvCkZSivmH7ezr4Ol1ZkRetQ92UQ7xJS7E0y6uXAGvdgpDnyqHCOFfhTS6yqltHtc3m7JZex327xkv6e69uAEOSiv++sifVUIE0h/5u3hZLvwmTPrkoRVY4wgZ4ieb86QPvhw4UPeYapOhCBk5RfjoEFIeYwPUw5rtOlpTyeBJiKMpH1+mDAoa+8HQytZoMrnnY1s612vINtY7jU5igMwIk6MitQpRGibnBVBHRc2A6aE+XS333ganFK9hX6TzNkpHUb66NINDZ8Rgb1thn3MABArGlomtM5/enrAixWExZp70TSElor7SBdBW57H7OZCYUCobZuPRDLsCO6LLKeVrbdygWeRqr/o=
+
+
+ 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==
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:profiles:attribute:basic
+
+
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+
+
+ http://localhost:8080/saml/v2/metadata IDP signing
+
+ 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==
+
+
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
+ urn:oasis:names:tc:SAML:2.0:profiles:attribute:basic
+
+
+
+
+
+
+
+
+ http://localhost:8080/saml/v2/metadata IDP signing
+
+ 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==
+
+
+
+
+`)
+
+var validSAMLMetadata2 = []byte(`
+
+
+
+
+
+ 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==
+
+
+
+
+
+
+ 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==
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+ Administrator
+ name@emailprovider.com
+
+`)
+
+func TestServer_TestIDProviderInstanceReduces(t *testing.T) {
+ instanceID := Instance.ID()
+
+ t.Run("test iam idp add reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ before := time.Now()
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.NameCondition(name),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.config.added
+ assert.Equal(t, instanceID, idp.InstanceID)
+ assert.Nil(t, idp.OrgID)
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateActive, idp.State)
+ assert.Equal(t, name, idp.Name)
+ assert.Equal(t, true, idp.AutoRegister)
+ assert.Equal(t, true, idp.AllowCreation)
+ assert.Equal(t, false, idp.AllowAutoUpdate)
+ assert.Equal(t, true, idp.AllowLinking)
+ assert.Nil(t, idp.AutoLinkingField)
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *idp.StylingType)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ assert.WithinRange(t, idp.CreatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp update reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ name = "new_" + name
+
+ before := time.Now()
+ _, err = AdminClient.UpdateIDP(IAMCTX, &admin.UpdateIDPRequest{
+ IdpId: addOIDC.IdpId,
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED,
+ AutoRegister: false,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.NameCondition(name),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.config.changed
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, name, idp.Name)
+ assert.Equal(t, false, idp.AutoRegister)
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED), *idp.StylingType)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp deactivate reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ // deactivate idp
+ before := time.Now()
+ _, err = AdminClient.DeactivateIDP(IAMCTX, &admin.DeactivateIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.config.deactivated
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateInactive, idp.State)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp config reactivate reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // deactivate idp
+ _, err = AdminClient.DeactivateIDP(IAMCTX, &admin.DeactivateIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+ // wait for idp to be deactivated
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateInactive, idp.State)
+ }, retryDuration, tick)
+
+ // reactivate idp
+ before := time.Now()
+ _, err = AdminClient.ReactivateIDP(IAMCTX, &admin.ReactivateIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.config.reactivated
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateActive, idp.State)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp config remove reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add idp
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // remove idp
+ _, err = AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+
+ // event iam.idp.config.remove
+ require.ErrorIs(t, &database.NoRowFoundError{}, err)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp oidc added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oidc.config.added
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Nil(t, oidc.OrgID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, addOIDC.IdpId, oidc.ID)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+
+ // oidc
+ assert.Equal(t, "issuer", oidc.Issuer)
+ assert.Equal(t, "clientID", oidc.ClientID)
+ assert.Equal(t, []string{"scope"}, oidc.Scopes)
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *oidc.StylingType)
+ assert.Equal(t, false, oidc.AutoRegister)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.IDPDisplayNameMapping)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.UserNameMapping)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp oidc changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check original values for OCID
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.IdpId), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addOIDC.IdpId, oidc.ID)
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = AdminClient.UpdateIDPOIDCConfig(IAMCTX, &admin.UpdateIDPOIDCConfigRequest{
+ IdpId: addOIDC.IdpId,
+ ClientId: "new_clientID",
+ ClientSecret: "new_clientSecret",
+ Issuer: "new_issuer",
+ Scopes: []string{"new_scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOIDC, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oidc.config.changed
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Nil(t, oidc.OrgID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, addOIDC.IdpId, updateOIDC.ID)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*updateOIDC.Type))
+ assert.WithinRange(t, updateOIDC.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Nil(t, oidc.OrgID)
+ assert.Equal(t, "new_issuer", updateOIDC.Issuer)
+ assert.Equal(t, "new_clientID", updateOIDC.ClientID)
+ assert.NotNil(t, oidc.ClientSecret)
+ assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.IDPDisplayNameMapping)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.UserNameMapping)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp jwt added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := AdminClient.AddJWTIDP(IAMCTX, &admin.AddJWTIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ JwtEndpoint: "jwtEndpoint",
+ Issuer: "issuer",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ jwt, err := idpRepo.GetJWT(IAMCTX, pool,
+ idpRepo.IDCondition(addJWT.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.jwt.config.added
+ // idp
+ assert.Equal(t, instanceID, jwt.InstanceID)
+ assert.Nil(t, jwt.OrgID)
+ assert.Equal(t, name, jwt.Name)
+ assert.Equal(t, addJWT.IdpId, jwt.ID)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*jwt.Type))
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *jwt.StylingType)
+
+ // jwt
+ assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint)
+ assert.Equal(t, "issuer", jwt.Issuer)
+ assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint)
+ assert.Equal(t, "headerName", jwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp jwt changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := AdminClient.AddJWTIDP(IAMCTX, &admin.AddJWTIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ JwtEndpoint: "jwtEndpoint",
+ Issuer: "issuer",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ before := time.Now()
+ _, err = AdminClient.UpdateIDPJWTConfig(IAMCTX, &admin.UpdateIDPJWTConfigRequest{
+ IdpId: addJWT.IdpId,
+ JwtEndpoint: "new_jwtEndpoint",
+ Issuer: "new_issuer",
+ KeysEndpoint: "new_keyEndpoint",
+ HeaderName: "new_headerName",
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateJWT, err := idpRepo.GetJWT(IAMCTX, pool,
+ idpRepo.IDCondition(addJWT.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event iam.idp.jwt.config.changed
+ // idp
+ assert.Equal(t, addJWT.IdpId, updateJWT.ID)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*updateJWT.Type))
+ assert.WithinRange(t, updateJWT.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "new_jwtEndpoint", updateJWT.JWTEndpoint)
+ assert.Equal(t, "new_issuer", updateJWT.Issuer)
+ assert.Equal(t, "new_keyEndpoint", updateJWT.KeysEndpoint)
+ assert.Equal(t, "new_headerName", updateJWT.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp oauth added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oauth
+ before := time.Now()
+ addOAuth, err := AdminClient.AddGenericOAuthProvider(IAMCTX, &admin.AddGenericOAuthProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authorizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ IdAttribute: "idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ UsePkce: false,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oauth
+ var oauth *domain.IDPOAuth
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oauth, err = idpRepo.GetOAuth(IAMCTX, pool, idpRepo.IDCondition(addOAuth.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.oauth.added
+ // idp
+ assert.Equal(t, instanceID, oauth.InstanceID)
+ assert.Nil(t, oauth.OrgID)
+ assert.Equal(t, addOAuth.Id, oauth.ID)
+ assert.Equal(t, name, oauth.Name)
+ assert.Equal(t, domain.IDPTypeOAuth, domain.IDPType(*oauth.Type))
+ assert.Equal(t, false, oauth.AllowLinking)
+ assert.Equal(t, false, oauth.AllowCreation)
+ assert.Equal(t, false, oauth.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*oauth.AutoLinkingField))
+ assert.WithinRange(t, oauth.CreatedAt, before, after)
+ assert.WithinRange(t, oauth.UpdatedAt, before, after)
+
+ // oauth
+ assert.Equal(t, "clientId", oauth.ClientID)
+ assert.NotNil(t, oauth.ClientSecret)
+ assert.Equal(t, "authorizationEndpoint", oauth.AuthorizationEndpoint)
+ assert.Equal(t, "tokenEndpoint", oauth.TokenEndpoint)
+ assert.Equal(t, "userEndpoint", oauth.UserEndpoint)
+ assert.Equal(t, []string{"scope"}, oauth.Scopes)
+ assert.Equal(t, "idAttribute", oauth.IDAttribute)
+ assert.Equal(t, false, oauth.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp oauth changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oauth
+ addOAuth, err := AdminClient.AddGenericOAuthProvider(IAMCTX, &admin.AddGenericOAuthProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authorizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ IdAttribute: "idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oauth
+ var oauth *domain.IDPOAuth
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oauth, err = idpRepo.GetOAuth(IAMCTX, pool, idpRepo.IDCondition(addOAuth.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addOAuth.Id, oauth.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ before := time.Now()
+ _, err = AdminClient.UpdateGenericOAuthProvider(IAMCTX, &admin.UpdateGenericOAuthProviderRequest{
+ Id: addOAuth.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ AuthorizationEndpoint: "new_authorizationEndpoint",
+ TokenEndpoint: "new_tokenEndpoint",
+ UserEndpoint: "new_userEndpoint",
+ Scopes: []string{"new_scope"},
+ IdAttribute: "new_idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ UsePkce: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOauth, err := idpRepo.GetOAuth(IAMCTX, pool,
+ idpRepo.IDCondition(addOAuth.Id),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event instance.idp.oauth.changed
+ // idp
+ assert.Equal(t, instanceID, oauth.InstanceID)
+ assert.Nil(t, oauth.OrgID)
+ assert.Equal(t, addOAuth.Id, updateOauth.ID)
+ assert.Equal(t, name, updateOauth.Name)
+ assert.Equal(t, domain.IDPTypeOAuth, domain.IDPType(*oauth.Type))
+ assert.Equal(t, true, updateOauth.AllowLinking)
+ assert.Equal(t, true, updateOauth.AllowCreation)
+ assert.Equal(t, true, updateOauth.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateOauth.AutoLinkingField))
+ assert.Equal(t, true, updateOauth.UsePKCE)
+ assert.WithinRange(t, updateOauth.UpdatedAt, before, after)
+
+ // oauth
+ assert.Equal(t, "new_clientId", updateOauth.ClientID)
+ assert.NotEqual(t, oauth.ClientSecret, updateOauth.ClientSecret)
+ assert.Equal(t, "new_authorizationEndpoint", updateOauth.AuthorizationEndpoint)
+ assert.Equal(t, "new_tokenEndpoint", updateOauth.TokenEndpoint)
+ assert.Equal(t, "new_userEndpoint", updateOauth.UserEndpoint)
+ assert.Equal(t, []string{"new_scope"}, updateOauth.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp oidc added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ before := time.Now()
+ addOIDC, err := AdminClient.AddGenericOIDCProvider(IAMCTX, &admin.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oidc
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err := idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.oidc added
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Nil(t, oidc.OrgID)
+ assert.Equal(t, addOIDC.Id, oidc.ID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ assert.Equal(t, false, oidc.AllowLinking)
+ assert.Equal(t, false, oidc.AllowCreation)
+ assert.Equal(t, false, oidc.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*oidc.AutoLinkingField))
+ assert.WithinRange(t, oidc.CreatedAt, before, after)
+ assert.WithinRange(t, oidc.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, addOIDC.Id, oidc.ID)
+ assert.Equal(t, "clientId", oidc.ClientID)
+ assert.NotNil(t, oidc.ClientSecret)
+ assert.Equal(t, []string{"scope"}, oidc.Scopes)
+ assert.Equal(t, "issuer", oidc.Issuer)
+ assert.Equal(t, false, oidc.IsIDTokenMapping)
+ assert.Equal(t, false, oidc.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instanceidp oidc changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := AdminClient.AddGenericOIDCProvider(IAMCTX, &admin.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oidc
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ before := time.Now()
+ _, err = AdminClient.UpdateGenericOIDCProvider(IAMCTX, &admin.UpdateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Name: name,
+ Issuer: "new_issuer",
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ IsIdTokenMapping: true,
+ UsePkce: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOIDC, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.Id),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+
+ // event instance.idp.oidc.changed
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Nil(t, oidc.OrgID)
+ assert.Equal(t, addOIDC.Id, oidc.ID)
+ assert.Equal(t, name, updateOIDC.Name)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ assert.Equal(t, true, updateOIDC.AllowLinking)
+ assert.Equal(t, true, updateOIDC.AllowCreation)
+ assert.Equal(t, true, updateOIDC.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateOIDC.AutoLinkingField))
+ assert.WithinRange(t, updateOIDC.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, addOIDC.Id, updateOIDC.ID)
+ assert.Equal(t, "new_clientId", updateOIDC.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes)
+ assert.Equal(t, true, updateOIDC.IsIDTokenMapping)
+ assert.Equal(t, true, updateOIDC.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp oidc migrated azure migration reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // create OIDC
+ addOIDC, err := AdminClient.AddGenericOIDCProvider(IAMCTX, &admin.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = AdminClient.MigrateGenericOIDCProvider(IAMCTX, &admin.MigrateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Template: &admin.MigrateGenericOIDCProviderRequest_Azure{
+ Azure: &admin.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ },
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.oidc.migrated.azure
+ // idp
+ assert.Equal(t, instanceID, azure.InstanceID)
+ assert.Nil(t, azure.OrgID)
+ assert.Equal(t, addOIDC.Id, azure.ID)
+ assert.Equal(t, name, azure.Name)
+ // type = azure
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*azure.Type))
+ assert.Equal(t, true, azure.AllowLinking)
+ assert.Equal(t, true, azure.AllowCreation)
+ assert.Equal(t, true, azure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*azure.AutoLinkingField))
+ assert.WithinRange(t, azure.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, "new_clientId", azure.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, azure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeOrganizations, azure.Tenant)
+ assert.Equal(t, true, azure.IsEmailVerified)
+ assert.Equal(t, []string{"new_scope"}, azure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp oidc migrated google migration reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // create OIDC
+ addOIDC, err := AdminClient.AddGenericOIDCProvider(IAMCTX, &admin.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = AdminClient.MigrateGenericOIDCProvider(IAMCTX, &admin.MigrateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Template: &admin.MigrateGenericOIDCProviderRequest_Google{
+ Google: &admin.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ },
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.oidc.migrated.google
+ // idp
+ assert.Equal(t, instanceID, google.InstanceID)
+ assert.Nil(t, google.OrgID)
+ assert.Equal(t, addOIDC.Id, google.ID)
+ assert.Equal(t, name, google.Name)
+ // type = google
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*google.Type))
+ assert.Equal(t, true, google.AllowLinking)
+ assert.Equal(t, true, google.AllowCreation)
+ assert.Equal(t, true, google.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*google.AutoLinkingField))
+ assert.WithinRange(t, google.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, "new_clientId", google.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, google.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, google.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp jwt added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ before := time.Now()
+ addJWT, err := AdminClient.AddJWTProvider(IAMCTX, &admin.AddJWTProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ JwtEndpoint: "jwtEndpoint",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for jwt
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ jwt, err := idpRepo.GetJWT(IAMCTX, pool, idpRepo.IDCondition(addJWT.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.jwt.added
+ // idp
+ assert.Equal(t, instanceID, jwt.InstanceID)
+ assert.Nil(t, jwt.OrgID)
+ assert.Equal(t, addJWT.Id, jwt.ID)
+ assert.Equal(t, name, jwt.Name)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*jwt.Type))
+ assert.Equal(t, false, jwt.AllowLinking)
+ assert.Equal(t, false, jwt.AllowCreation)
+ assert.Equal(t, false, jwt.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*jwt.AutoLinkingField))
+ assert.WithinRange(t, jwt.CreatedAt, before, after)
+ assert.WithinRange(t, jwt.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint)
+ assert.Equal(t, "issuer", jwt.Issuer)
+ assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint)
+ assert.Equal(t, "headerName", jwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp jwt changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := AdminClient.AddJWTProvider(IAMCTX, &admin.AddJWTProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ JwtEndpoint: "jwtEndpoint",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ require.NoError(t, err)
+
+ name = "new_" + name
+ // change jwt
+ before := time.Now()
+ _, err = AdminClient.UpdateJWTProvider(IAMCTX, &admin.UpdateJWTProviderRequest{
+ Id: addJWT.Id,
+ Name: name,
+ Issuer: "new_issuer",
+ JwtEndpoint: "new_jwtEndpoint",
+ KeysEndpoint: "new_keyEndpoint",
+ HeaderName: "new_headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for jwt
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ jwt, err := idpRepo.GetJWT(IAMCTX, pool, idpRepo.IDCondition(addJWT.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.jwt.added
+ // idp
+ assert.Equal(t, instanceID, jwt.InstanceID)
+ assert.Nil(t, jwt.OrgID)
+ assert.Equal(t, addJWT.Id, jwt.ID)
+ assert.Equal(t, name, jwt.Name)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*jwt.Type))
+ assert.Equal(t, true, jwt.AllowLinking)
+ assert.Equal(t, true, jwt.AllowCreation)
+ assert.Equal(t, true, jwt.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*jwt.AutoLinkingField))
+ assert.WithinRange(t, jwt.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "new_jwtEndpoint", jwt.JWTEndpoint)
+ assert.Equal(t, "new_issuer", jwt.Issuer)
+ assert.Equal(t, "new_keyEndpoint", jwt.KeysEndpoint)
+ assert.Equal(t, "new_headerName", jwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp azure added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add azure
+ before := time.Now()
+ addAzure, err := AdminClient.AddAzureADProvider(IAMCTX, &admin.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for azure
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.azure.added
+ // idp
+ assert.Equal(t, instanceID, azure.InstanceID)
+ assert.Nil(t, azure.OrgID)
+ assert.Equal(t, addAzure.Id, azure.ID)
+ assert.Equal(t, name, azure.Name)
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*azure.Type))
+ assert.Equal(t, true, azure.AllowLinking)
+ assert.Equal(t, true, azure.AllowCreation)
+ assert.Equal(t, true, azure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*azure.AutoLinkingField))
+ assert.WithinRange(t, azure.UpdatedAt, before, after)
+
+ // azure
+ assert.Equal(t, "clientId", azure.ClientID)
+ assert.NotNil(t, azure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeOrganizations, azure.Tenant)
+ assert.Equal(t, true, azure.IsEmailVerified)
+ assert.Equal(t, []string{"scope"}, azure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp azure changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add azure
+ addAzure, err := AdminClient.AddAzureADProvider(IAMCTX, &admin.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: false,
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var azure *domain.IDPAzureAD
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err = idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addAzure.Id, azure.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change azure
+ before := time.Now()
+ _, err = AdminClient.UpdateAzureADProvider(IAMCTX, &admin.UpdateAzureADProviderRequest{
+ Id: addAzure.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_CONSUMERS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateAzure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.azure.changed
+ // idp
+ assert.Equal(t, instanceID, updateAzure.InstanceID)
+ assert.Nil(t, updateAzure.OrgID)
+ assert.Equal(t, addAzure.Id, updateAzure.ID)
+ assert.Equal(t, name, updateAzure.Name)
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*updateAzure.Type))
+ assert.Equal(t, true, updateAzure.AllowLinking)
+ assert.Equal(t, true, updateAzure.AllowCreation)
+ assert.Equal(t, true, updateAzure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*updateAzure.AutoLinkingField))
+ assert.WithinRange(t, updateAzure.UpdatedAt, before, after)
+
+ // azure
+ assert.Equal(t, "new_clientId", updateAzure.ClientID)
+ assert.NotEqual(t, azure.ClientSecret, updateAzure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeConsumers, updateAzure.Tenant)
+ assert.Equal(t, true, updateAzure.IsEmailVerified)
+ assert.Equal(t, []string{"new_scope"}, updateAzure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp github added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github
+ before := time.Now()
+ addGithub, err := AdminClient.AddGitHubProvider(IAMCTX, &admin.AddGitHubProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for github
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ github, err := idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.github.added
+ // idp
+ assert.Equal(t, instanceID, github.InstanceID)
+ assert.Nil(t, github.OrgID)
+ assert.Equal(t, addGithub.Id, github.ID)
+ assert.Equal(t, name, github.Name)
+ assert.Equal(t, domain.IDPTypeGitHub, domain.IDPType(*github.Type))
+ assert.Equal(t, false, github.AllowLinking)
+ assert.Equal(t, false, github.AllowCreation)
+ assert.Equal(t, false, github.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*github.AutoLinkingField))
+ assert.WithinRange(t, github.UpdatedAt, before, after)
+
+ assert.Equal(t, "clientId", github.ClientID)
+ assert.NotNil(t, github.ClientSecret)
+ assert.Equal(t, []string{"scope"}, github.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp github changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github
+ addGithub, err := AdminClient.AddGitHubProvider(IAMCTX, &admin.AddGitHubProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var github *domain.IDPGithub
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ github, err = idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addGithub.Id, github.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change github
+ before := time.Now()
+ _, err = AdminClient.UpdateGitHubProvider(IAMCTX, &admin.UpdateGitHubProviderRequest{
+ Id: addGithub.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGithub, err := idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.github.changed
+ // idp
+ assert.Equal(t, instanceID, updateGithub.InstanceID)
+ assert.Nil(t, updateGithub.OrgID)
+ assert.Equal(t, addGithub.Id, updateGithub.ID)
+ assert.Equal(t, name, updateGithub.Name)
+ assert.Equal(t, domain.IDPTypeGitHub, domain.IDPType(*updateGithub.Type))
+ assert.Equal(t, true, updateGithub.AllowLinking)
+ assert.Equal(t, true, updateGithub.AllowCreation)
+ assert.Equal(t, true, updateGithub.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGithub.AutoLinkingField))
+ assert.WithinRange(t, updateGithub.UpdatedAt, before, after)
+
+ // github
+ assert.Equal(t, "new_clientId", updateGithub.ClientID)
+ assert.NotEqual(t, github.ClientSecret, updateGithub.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGithub.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp github enterprise added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github enterprise
+ before := time.Now()
+ addGithubEnterprise, err := AdminClient.AddGitHubEnterpriseServerProvider(IAMCTX, &admin.AddGitHubEnterpriseServerProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authorizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for github enterprise
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githubEnterprise, err := idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.github_enterprise.added
+ // idp
+ assert.Equal(t, instanceID, githubEnterprise.InstanceID)
+ assert.Nil(t, githubEnterprise.OrgID)
+ assert.Equal(t, addGithubEnterprise.Id, githubEnterprise.ID)
+ assert.Equal(t, name, githubEnterprise.Name)
+ assert.Equal(t, domain.IDPTypeGitHubEnterprise, domain.IDPType(*githubEnterprise.Type))
+ assert.Equal(t, false, githubEnterprise.AllowLinking)
+ assert.Equal(t, false, githubEnterprise.AllowCreation)
+ assert.Equal(t, false, githubEnterprise.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*githubEnterprise.AutoLinkingField))
+ assert.WithinRange(t, githubEnterprise.CreatedAt, before, after)
+ assert.WithinRange(t, githubEnterprise.UpdatedAt, before, after)
+
+ // github enterprise
+ assert.Equal(t, "clientId", githubEnterprise.ClientID)
+ assert.NotNil(t, githubEnterprise.ClientSecret)
+ assert.Equal(t, "authorizationEndpoint", githubEnterprise.AuthorizationEndpoint)
+ assert.Equal(t, "tokenEndpoint", githubEnterprise.TokenEndpoint)
+ assert.Equal(t, "userEndpoint", githubEnterprise.UserEndpoint)
+ assert.Equal(t, []string{"scope"}, githubEnterprise.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp github enterprise changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github enterprise
+ addGithubEnterprise, err := AdminClient.AddGitHubEnterpriseServerProvider(IAMCTX, &admin.AddGitHubEnterpriseServerProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authorizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var githubEnterprise *domain.IDPGithubEnterprise
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githubEnterprise, err = idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addGithubEnterprise.Id, githubEnterprise.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change github enterprise
+ before := time.Now()
+ _, err = AdminClient.UpdateGitHubEnterpriseServerProvider(IAMCTX, &admin.UpdateGitHubEnterpriseServerProviderRequest{
+ Id: addGithubEnterprise.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ AuthorizationEndpoint: "new_authorizationEndpoint",
+ TokenEndpoint: "new_tokenEndpoint",
+ UserEndpoint: "new_userEndpoint",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGithubEnterprise, err := idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.github_enterprise.changed
+ // idp
+ assert.Equal(t, instanceID, githubEnterprise.InstanceID)
+ assert.Nil(t, githubEnterprise.OrgID)
+ assert.Equal(t, addGithubEnterprise.Id, updateGithubEnterprise.ID)
+ assert.Equal(t, name, updateGithubEnterprise.Name)
+ assert.Equal(t, domain.IDPTypeGitHubEnterprise, domain.IDPType(*updateGithubEnterprise.Type))
+ assert.Equal(t, false, updateGithubEnterprise.AllowLinking)
+ assert.Equal(t, false, updateGithubEnterprise.AllowCreation)
+ assert.Equal(t, false, updateGithubEnterprise.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*updateGithubEnterprise.AutoLinkingField))
+ assert.WithinRange(t, updateGithubEnterprise.UpdatedAt, before, after)
+
+ // github enterprise
+ assert.Equal(t, "new_clientId", updateGithubEnterprise.ClientID)
+ assert.NotNil(t, updateGithubEnterprise.ClientSecret)
+ assert.Equal(t, "new_authorizationEndpoint", updateGithubEnterprise.AuthorizationEndpoint)
+ assert.Equal(t, "new_tokenEndpoint", updateGithubEnterprise.TokenEndpoint)
+ assert.Equal(t, "new_userEndpoint", updateGithubEnterprise.UserEndpoint)
+ assert.Equal(t, []string{"new_scope"}, updateGithubEnterprise.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp gitlab added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab
+ before := time.Now()
+ addGithub, err := AdminClient.AddGitLabProvider(IAMCTX, &admin.AddGitLabProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for gitlab
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ gitlab, err := idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.gitlab.added
+ // idp
+ assert.Equal(t, instanceID, gitlab.InstanceID)
+ assert.Nil(t, gitlab.OrgID)
+ assert.Equal(t, addGithub.Id, gitlab.ID)
+ assert.Equal(t, name, gitlab.Name)
+ assert.Equal(t, domain.IDPTypeGitLab, domain.IDPType(*gitlab.Type))
+ assert.Equal(t, false, gitlab.AllowLinking)
+ assert.Equal(t, false, gitlab.AllowCreation)
+ assert.Equal(t, false, gitlab.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*gitlab.AutoLinkingField))
+ assert.WithinRange(t, gitlab.CreatedAt, before, after)
+ assert.WithinRange(t, gitlab.UpdatedAt, before, after)
+
+ // gitlab
+ assert.Equal(t, "clientId", gitlab.ClientID)
+ assert.NotNil(t, gitlab.ClientSecret)
+ assert.Equal(t, []string{"scope"}, gitlab.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp gitlab changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab
+ addGitlab, err := AdminClient.AddGitLabProvider(IAMCTX, &admin.AddGitLabProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var githlab *domain.IDPGitlab
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githlab, err = idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGitlab.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addGitlab.Id, githlab.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change gitlab
+ before := time.Now()
+ _, err = AdminClient.UpdateGitLabProvider(IAMCTX, &admin.UpdateGitLabProviderRequest{
+ Id: addGitlab.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for gitlab
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGitlab, err := idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGitlab.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.gitlab.changed
+ // idp
+ assert.Equal(t, instanceID, updateGitlab.InstanceID)
+ assert.Nil(t, updateGitlab.OrgID)
+ assert.Equal(t, addGitlab.Id, updateGitlab.ID)
+ assert.Equal(t, name, updateGitlab.Name)
+ assert.Equal(t, true, updateGitlab.AllowLinking)
+ assert.Equal(t, true, updateGitlab.AllowCreation)
+ assert.Equal(t, true, updateGitlab.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGitlab.AutoLinkingField))
+ assert.WithinRange(t, updateGitlab.UpdatedAt, before, after)
+
+ // gitlab
+ assert.Equal(t, "new_clientId", updateGitlab.ClientID)
+ assert.NotEqual(t, githlab.ClientSecret, updateGitlab.ClientSecret)
+ assert.Equal(t, domain.IDPTypeGitLab, domain.IDPType(*updateGitlab.Type))
+ assert.Equal(t, []string{"new_scope"}, updateGitlab.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp gitlab self hosted added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab self hosted
+ before := time.Now()
+ addGitlabSelfHosted, err := AdminClient.AddGitLabSelfHostedProvider(IAMCTX, &admin.AddGitLabSelfHostedProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for gitlab self hosted
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ gitlabSelfHosted, err := idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.gitlab_self_hosted.added
+ // idp
+ assert.Equal(t, instanceID, gitlabSelfHosted.InstanceID)
+ assert.Nil(t, gitlabSelfHosted.OrgID)
+ assert.Equal(t, addGitlabSelfHosted.Id, gitlabSelfHosted.ID)
+ assert.Equal(t, name, gitlabSelfHosted.Name)
+ assert.Equal(t, domain.IDPTypeGitLabSelfHosted, domain.IDPType(*gitlabSelfHosted.Type))
+ assert.Equal(t, false, gitlabSelfHosted.AllowLinking)
+ assert.Equal(t, false, gitlabSelfHosted.AllowCreation)
+ assert.Equal(t, false, gitlabSelfHosted.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*gitlabSelfHosted.AutoLinkingField))
+ assert.WithinRange(t, gitlabSelfHosted.CreatedAt, before, after)
+ assert.WithinRange(t, gitlabSelfHosted.UpdatedAt, before, after)
+
+ // gitlab self hosted
+ assert.Equal(t, "clientId", gitlabSelfHosted.ClientID)
+ assert.Equal(t, "issuer", gitlabSelfHosted.Issuer)
+ assert.NotNil(t, gitlabSelfHosted.ClientSecret)
+ assert.Equal(t, []string{"scope"}, gitlabSelfHosted.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp gitlab self hosted changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab self hosted
+ addGitlabSelfHosted, err := AdminClient.AddGitLabSelfHostedProvider(IAMCTX, &admin.AddGitLabSelfHostedProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ 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()
+
+ var githlabSelfHosted *domain.IDPGitlabSelfHosting
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githlabSelfHosted, err = idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addGitlabSelfHosted.Id, githlabSelfHosted.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change gitlab self hosted
+ before := time.Now()
+ _, err = AdminClient.UpdateGitLabSelfHostedProvider(IAMCTX, &admin.UpdateGitLabSelfHostedProviderRequest{
+ Id: addGitlabSelfHosted.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ Issuer: "new_issuer",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for gitlab self hosted
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGitlabSelfHosted, err := idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.gitlab_self_hosted.changed
+ // idp
+ assert.Equal(t, instanceID, updateGitlabSelfHosted.InstanceID)
+ assert.Nil(t, updateGitlabSelfHosted.OrgID)
+ assert.Equal(t, addGitlabSelfHosted.Id, updateGitlabSelfHosted.ID)
+ assert.Equal(t, name, updateGitlabSelfHosted.Name)
+ assert.Equal(t, domain.IDPTypeGitLabSelfHosted, domain.IDPType(*updateGitlabSelfHosted.Type))
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowLinking)
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowCreation)
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGitlabSelfHosted.AutoLinkingField))
+ assert.WithinRange(t, updateGitlabSelfHosted.UpdatedAt, before, after)
+
+ // gitlab self hosted
+ assert.Equal(t, "new_clientId", updateGitlabSelfHosted.ClientID)
+ assert.Equal(t, "new_issuer", updateGitlabSelfHosted.Issuer)
+ assert.NotEqual(t, githlabSelfHosted.ClientSecret, updateGitlabSelfHosted.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGitlabSelfHosted.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp google added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add google
+ before := time.Now()
+ addGoogle, err := AdminClient.AddGoogleProvider(IAMCTX, &admin.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for google
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.google.added
+ // idp
+ assert.Equal(t, instanceID, google.InstanceID)
+ assert.Nil(t, google.OrgID)
+ assert.Equal(t, addGoogle.Id, google.ID)
+ assert.Equal(t, name, google.Name)
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*google.Type))
+ assert.Equal(t, false, google.AllowLinking)
+ assert.Equal(t, false, google.AllowCreation)
+ assert.Equal(t, false, google.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*google.AutoLinkingField))
+ assert.WithinRange(t, google.CreatedAt, before, after)
+ assert.WithinRange(t, google.UpdatedAt, before, after)
+
+ // google
+ assert.Equal(t, "clientId", google.ClientID)
+ assert.NotNil(t, google.ClientSecret)
+ assert.Equal(t, []string{"scope"}, google.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance idp google changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add google
+ addGoogle, err := AdminClient.AddGoogleProvider(IAMCTX, &admin.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ 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()
+
+ var google *domain.IDPGoogle
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err = idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addGoogle.Id, google.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change google
+ before := time.Now()
+ _, err = AdminClient.UpdateGoogleProvider(IAMCTX, &admin.UpdateGoogleProviderRequest{
+ Id: addGoogle.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for google
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGoogle, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.google.changed
+ // idp
+ assert.Equal(t, instanceID, updateGoogle.InstanceID)
+ assert.Nil(t, updateGoogle.OrgID)
+ assert.Equal(t, addGoogle.Id, updateGoogle.ID)
+ assert.Equal(t, name, updateGoogle.Name)
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*updateGoogle.Type))
+ assert.Equal(t, true, updateGoogle.AllowLinking)
+ assert.Equal(t, true, updateGoogle.AllowCreation)
+ assert.Equal(t, true, updateGoogle.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGoogle.AutoLinkingField))
+ assert.WithinRange(t, updateGoogle.UpdatedAt, before, after)
+
+ // google
+ assert.Equal(t, "new_clientId", updateGoogle.ClientID)
+ assert.NotEqual(t, google.ClientSecret, updateGoogle.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGoogle.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance ldap added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add ldap
+ before := time.Now()
+ addLdap, err := AdminClient.AddLDAPProvider(IAMCTX, &admin.AddLDAPProviderRequest{
+ Name: name,
+ Servers: []string{"servers"},
+ StartTls: true,
+ BaseDn: "baseDN",
+ BindDn: "bindND",
+ BindPassword: "bindPassword",
+ UserBase: "userBase",
+ UserObjectClasses: []string{"userOhjectClasses"},
+ UserFilters: []string{"userFilters"},
+ Timeout: durationpb.New(time.Minute),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "idAttribute",
+ FirstNameAttribute: "firstNameAttribute",
+ LastNameAttribute: "lastNameAttribute",
+ DisplayNameAttribute: "displayNameAttribute",
+ NickNameAttribute: "nickNameAttribute",
+ PreferredUsernameAttribute: "preferredUsernameAttribute",
+ EmailAttribute: "emailAttribute",
+ EmailVerifiedAttribute: "emailVerifiedAttribute",
+ PhoneAttribute: "phoneAttribute",
+ PhoneVerifiedAttribute: "phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "preferredLanguageAttribute",
+ AvatarUrlAttribute: "avatarUrlAttribute",
+ ProfileAttribute: "profileAttribute",
+ },
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ ldap, err := idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.ldap.v2.added
+ // idp
+ assert.Equal(t, instanceID, ldap.InstanceID)
+ assert.Nil(t, ldap.OrgID)
+ assert.Equal(t, addLdap.Id, ldap.ID)
+ assert.Equal(t, name, ldap.Name)
+ assert.Equal(t, domain.IDPTypeLDAP, domain.IDPType(*ldap.Type))
+ assert.Equal(t, false, ldap.AllowLinking)
+ assert.Equal(t, false, ldap.AllowCreation)
+ assert.Equal(t, false, ldap.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*ldap.AutoLinkingField))
+ assert.WithinRange(t, ldap.CreatedAt, before, after)
+ assert.WithinRange(t, ldap.UpdatedAt, before, after)
+
+ // ldap
+ assert.Equal(t, []string{"servers"}, ldap.Servers)
+ assert.Equal(t, true, ldap.StartTLS)
+ assert.Equal(t, "baseDN", ldap.BaseDN)
+ assert.Equal(t, "bindND", ldap.BindDN)
+ assert.NotNil(t, ldap.BindPassword)
+ assert.Equal(t, "userBase", ldap.UserBase)
+ assert.Equal(t, []string{"userOhjectClasses"}, ldap.UserObjectClasses)
+ assert.Equal(t, []string{"userFilters"}, ldap.UserFilters)
+ assert.Equal(t, time.Minute, ldap.Timeout)
+ assert.Equal(t, "idAttribute", ldap.IDAttribute)
+ assert.Equal(t, "firstNameAttribute", ldap.FirstNameAttribute)
+ assert.Equal(t, "lastNameAttribute", ldap.LastNameAttribute)
+ assert.Equal(t, "displayNameAttribute", ldap.DisplayNameAttribute)
+ assert.Equal(t, "nickNameAttribute", ldap.NickNameAttribute)
+ assert.Equal(t, "preferredUsernameAttribute", ldap.PreferredUsernameAttribute)
+ assert.Equal(t, "emailAttribute", ldap.EmailAttribute)
+ assert.Equal(t, "emailVerifiedAttribute", ldap.EmailVerifiedAttribute)
+ assert.Equal(t, "phoneAttribute", ldap.PhoneAttribute)
+ assert.Equal(t, "phoneVerifiedAttribute", ldap.PhoneVerifiedAttribute)
+ assert.Equal(t, "preferredLanguageAttribute", ldap.PreferredLanguageAttribute)
+ assert.Equal(t, "avatarUrlAttribute", ldap.AvatarURLAttribute)
+ assert.Equal(t, "profileAttribute", ldap.ProfileAttribute)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance ldap changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add ldap
+ addLdap, err := AdminClient.AddLDAPProvider(IAMCTX, &admin.AddLDAPProviderRequest{
+ Name: name,
+ Servers: []string{"servers"},
+ StartTls: true,
+ BaseDn: "baseDN",
+ BindDn: "bindND",
+ BindPassword: "bindPassword",
+ UserBase: "userBase",
+ UserObjectClasses: []string{"userOhjectClasses"},
+ UserFilters: []string{"userFilters"},
+ Timeout: durationpb.New(time.Minute),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "idAttribute",
+ FirstNameAttribute: "firstNameAttribute",
+ LastNameAttribute: "lastNameAttribute",
+ DisplayNameAttribute: "displayNameAttribute",
+ NickNameAttribute: "nickNameAttribute",
+ PreferredUsernameAttribute: "preferredUsernameAttribute",
+ EmailAttribute: "emailAttribute",
+ EmailVerifiedAttribute: "emailVerifiedAttribute",
+ PhoneAttribute: "phoneAttribute",
+ PhoneVerifiedAttribute: "phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "preferredLanguageAttribute",
+ AvatarUrlAttribute: "avatarUrlAttribute",
+ ProfileAttribute: "profileAttribute",
+ },
+ 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()
+
+ var ldap *domain.IDPLDAP
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ ldap, err = idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addLdap.Id, ldap.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change ldap
+ before := time.Now()
+ _, err = AdminClient.UpdateLDAPProvider(IAMCTX, &admin.UpdateLDAPProviderRequest{
+ Id: addLdap.Id,
+ Name: name,
+ Servers: []string{"new_servers"},
+ StartTls: false,
+ BaseDn: "new_baseDN",
+ BindDn: "new_bindND",
+ BindPassword: "new_bindPassword",
+ UserBase: "new_userBase",
+ UserObjectClasses: []string{"new_userOhjectClasses"},
+ UserFilters: []string{"new_userFilters"},
+ Timeout: durationpb.New(time.Second),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "new_idAttribute",
+ FirstNameAttribute: "new_firstNameAttribute",
+ LastNameAttribute: "new_lastNameAttribute",
+ DisplayNameAttribute: "new_displayNameAttribute",
+ NickNameAttribute: "new_nickNameAttribute",
+ PreferredUsernameAttribute: "new_preferredUsernameAttribute",
+ EmailAttribute: "new_emailAttribute",
+ EmailVerifiedAttribute: "new_emailVerifiedAttribute",
+ PhoneAttribute: "new_phoneAttribute",
+ PhoneVerifiedAttribute: "new_phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "new_preferredLanguageAttribute",
+ AvatarUrlAttribute: "new_avatarUrlAttribute",
+ ProfileAttribute: "new_profileAttribute",
+ },
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for ldap
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateLdap, err := idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, nil)
+ require.NoError(t, err)
+
+ // event instance.idp.ldap.v2.changed
+ // idp
+ assert.Equal(t, instanceID, updateLdap.InstanceID)
+ assert.Nil(t, updateLdap.OrgID)
+ assert.Equal(t, addLdap.Id, updateLdap.ID)
+ assert.Equal(t, name, updateLdap.Name)
+ assert.Equal(t, domain.IDPTypeLDAP, domain.IDPType(*updateLdap.Type))
+ assert.Equal(t, true, updateLdap.AllowLinking)
+ assert.Equal(t, true, updateLdap.AllowCreation)
+ assert.Equal(t, true, updateLdap.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateLdap.AutoLinkingField))
+ assert.WithinRange(t, updateLdap.UpdatedAt, before, after)
+
+ // ldap
+ assert.Equal(t, []string{"new_servers"}, updateLdap.Servers)
+ assert.Equal(t, false, updateLdap.StartTLS)
+ assert.Equal(t, "new_baseDN", updateLdap.BaseDN)
+ assert.Equal(t, "new_bindND", updateLdap.BindDN)
+ assert.NotEqual(t, ldap.BindPassword, updateLdap.BindPassword)
+ assert.Equal(t, "new_userBase", updateLdap.UserBase)
+ assert.Equal(t, []string{"new_userOhjectClasses"}, updateLdap.UserObjectClasses)
+ assert.Equal(t, []string{"new_userFilters"}, updateLdap.UserFilters)
+ assert.Equal(t, time.Second, updateLdap.Timeout)
+ assert.Equal(t, "new_idAttribute", updateLdap.IDAttribute)
+ assert.Equal(t, "new_firstNameAttribute", updateLdap.FirstNameAttribute)
+ assert.Equal(t, "new_lastNameAttribute", updateLdap.LastNameAttribute)
+ assert.Equal(t, "new_displayNameAttribute", updateLdap.DisplayNameAttribute)
+ assert.Equal(t, "new_nickNameAttribute", updateLdap.NickNameAttribute)
+ assert.Equal(t, "new_preferredUsernameAttribute", updateLdap.PreferredUsernameAttribute)
+ assert.Equal(t, "new_emailAttribute", updateLdap.EmailAttribute)
+ assert.Equal(t, "new_emailVerifiedAttribute", updateLdap.EmailVerifiedAttribute)
+ assert.Equal(t, "new_phoneAttribute", updateLdap.PhoneAttribute)
+ assert.Equal(t, "new_phoneVerifiedAttribute", updateLdap.PhoneVerifiedAttribute)
+ assert.Equal(t, "new_preferredLanguageAttribute", updateLdap.PreferredLanguageAttribute)
+ assert.Equal(t, "new_avatarUrlAttribute", updateLdap.AvatarURLAttribute)
+ assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance apple added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add apple
+ before := time.Now()
+ addApple, err := AdminClient.AddAppleProvider(IAMCTX, &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,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ apple, err := idpRepo.GetApple(IAMCTX, pool, 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, domain.IDPType(*apple.Type))
+ assert.Equal(t, false, apple.AllowLinking)
+ assert.Equal(t, false, apple.AllowCreation)
+ assert.Equal(t, false, apple.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*apple.AutoLinkingField))
+ assert.WithinRange(t, apple.CreatedAt, before, after)
+ assert.WithinRange(t, apple.UpdatedAt, before, after)
+
+ // 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(IAMCTX, &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()
+
+ var apple *domain.IDPApple
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ apple, err = idpRepo.GetApple(IAMCTX, pool, idpRepo.IDCondition(addApple.Id), instanceID, nil)
+ require.NoError(t, err)
+ assert.Equal(t, addApple.Id, apple.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change apple
+ before := time.Now()
+ _, err = AdminClient.UpdateAppleProvider(IAMCTX, &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,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for apple
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateApple, err := idpRepo.GetApple(IAMCTX, pool, 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, domain.IDPType(*updateApple.Type))
+ assert.Equal(t, true, updateApple.AllowLinking)
+ assert.Equal(t, true, updateApple.AllowCreation)
+ assert.Equal(t, true, updateApple.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateApple.AutoLinkingField))
+ assert.WithinRange(t, updateApple.UpdatedAt, before, after)
+
+ // 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
+ before := time.Now()
+ addSAML, err := AdminClient.AddSAMLProvider(IAMCTX, &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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ saml, err := idpRepo.GetSAML(IAMCTX, pool, 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, domain.IDPType(*saml.Type))
+ assert.Equal(t, false, saml.AllowLinking)
+ assert.Equal(t, false, saml.AllowCreation)
+ assert.Equal(t, false, saml.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*saml.AutoLinkingField))
+ assert.WithinRange(t, saml.CreatedAt, before, after)
+ assert.WithinRange(t, saml.UpdatedAt, before, after)
+
+ // 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)
+ assert.Equal(t, "http://www.w3.org/2000/09/xmldsig#rsa-sha1", saml.SignatureAlgorithm)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance saml changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+ federatedLogoutEnabled := false
+
+ // add saml
+ addSAML, err := AdminClient.AddSAMLProvider(IAMCTX, &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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var saml *domain.IDPSAML
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ saml, err = idpRepo.GetSAML(IAMCTX, pool, 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
+ before := time.Now()
+ _, err = AdminClient.UpdateSAMLProvider(IAMCTX, &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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for apple
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateSAML, err := idpRepo.GetSAML(IAMCTX, pool, 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, domain.IDPType(*updateSAML.Type))
+ assert.Equal(t, true, updateSAML.AllowLinking)
+ assert.Equal(t, true, updateSAML.AllowCreation)
+ assert.Equal(t, true, updateSAML.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateSAML.AutoLinkingField))
+ assert.WithinRange(t, updateSAML.UpdatedAt, before, after)
+
+ // saml
+ assert.Equal(t, validSAMLMetadata2, updateSAML.Metadata)
+ assert.NotNil(t, updateSAML.Key)
+ assert.NotNil(t, updateSAML.Certificate)
+ 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)
+ assert.Equal(t, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", updateSAML.SignatureAlgorithm)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instance iam remove reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add idp
+ addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, &admin.AddOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check idp exists
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.NoError(t, err)
+ }, retryDuration, tick)
+
+ // remove idp
+ _, err = AdminClient.DeleteProvider(IAMCTX, &admin.DeleteProviderRequest{
+ Id: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+
+ // check idp is removed
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ nil,
+ )
+ require.ErrorIs(t, &database.NoRowFoundError{}, err)
+ }, retryDuration, tick)
+ })
+}
diff --git a/backend/v3/storage/database/events_testing/id_provider_org_test.go b/backend/v3/storage/database/events_testing/id_provider_org_test.go
new file mode 100644
index 00000000000..d361f6276fb
--- /dev/null
+++ b/backend/v3/storage/database/events_testing/id_provider_org_test.go
@@ -0,0 +1,2414 @@
+//go:build integration
+
+package events_test
+
+import (
+ "testing"
+ "time"
+
+ "github.com/brianvoe/gofakeit/v6"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ durationpb "google.golang.org/protobuf/types/known/durationpb"
+
+ "github.com/zitadel/zitadel/backend/v3/domain"
+ "github.com/zitadel/zitadel/backend/v3/storage/database"
+ "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/pkg/grpc/idp"
+ idp_grpc "github.com/zitadel/zitadel/pkg/grpc/idp"
+ "github.com/zitadel/zitadel/pkg/grpc/management"
+)
+
+func TestServer_TestIDProviderOrgReduces(t *testing.T) {
+ instanceID := Instance.ID()
+ orgID := Instance.DefaultOrg.Id
+
+ t.Run("test iam idp add reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ before := time.Now()
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.NameCondition(name),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.config.added
+ assert.Equal(t, instanceID, idp.InstanceID)
+ assert.Equal(t, orgID, *idp.OrgID)
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateActive, idp.State)
+ assert.Equal(t, name, idp.Name)
+ assert.Equal(t, true, idp.AutoRegister)
+ assert.Equal(t, true, idp.AllowCreation)
+ assert.Equal(t, false, idp.AllowAutoUpdate)
+ assert.Equal(t, true, idp.AllowLinking)
+ assert.Nil(t, idp.AutoLinkingField)
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *idp.StylingType)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ assert.WithinRange(t, idp.CreatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ // t.Run("test iam idp update reduces", func(t *testing.T) {
+ // name := gofakeit.Name()
+
+ // addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ // Name: name,
+ // StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ // ClientId: "clientID",
+ // ClientSecret: "clientSecret",
+ // Issuer: "issuer",
+ // Scopes: []string{"scope"},
+ // DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ // UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ // AutoRegister: true,
+ // })
+ // require.NoError(t, err)
+
+ // name = "new_" + name
+
+ // before := time.Now()
+ // _, err = MgmtClient.UpdateOrgIDP(IAMCTX, &management.UpdateOrgIDPRequest{
+ // IdpId: addOIDC.IdpId,
+ // Name: name,
+ // StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED,
+ // AutoRegister: false,
+ // })
+ // after := time.Now()
+ // require.NoError(t, err)
+
+ // idpRepo := repository.IDProviderRepository()
+
+ // retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ // assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ // idp, err := idpRepo.Get(IAMCTX, pool,
+ // idpRepo.NameCondition(name),
+ // instanceID,
+ // &orgID,
+ // )
+ // require.NoError(t, err)
+
+ // // event org.idp.config.changed
+ // assert.Equal(t, addOIDC.IdpId, idp.ID)
+ // assert.Equal(t, name, idp.Name)
+ // assert.Equal(t, false, idp.AutoRegister)
+ // assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_UNSPECIFIED), *idp.StylingType)
+ // assert.WithinRange(t, idp.UpdatedAt, before, after)
+ // }, retryDuration, tick)
+ // })
+
+ t.Run("test iam idp deactivate reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ // deactivate idp
+ before := time.Now()
+ _, err = MgmtClient.DeactivateOrgIDP(IAMCTX, &management.DeactivateOrgIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.config.deactivated
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateInactive, idp.State)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp reactivate reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // deactivate idp
+ _, err = MgmtClient.DeactivateOrgIDP(IAMCTX, &management.DeactivateOrgIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+ // wait for idp to be deactivated
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateInactive, idp.State)
+ }, retryDuration, tick)
+
+ // reactivate idp
+ before := time.Now()
+ _, err = MgmtClient.ReactivateOrgIDP(IAMCTX, &management.ReactivateOrgIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ idp, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.config.reactivated
+ assert.Equal(t, addOIDC.IdpId, idp.ID)
+ assert.Equal(t, domain.IDPStateActive, idp.State)
+ assert.WithinRange(t, idp.UpdatedAt, before, after)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp remove reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add idp
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // remove idp
+ _, err = MgmtClient.RemoveOrgIDP(IAMCTX, &management.RemoveOrgIDPRequest{
+ IdpId: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*20)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+
+ // event org.idp.config.remove
+ require.ErrorIs(t, &database.NoRowFoundError{}, err)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp oidc added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oidc.config.added
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Equal(t, orgID, *oidc.OrgID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, addOIDC.IdpId, oidc.ID)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+
+ // oidc
+ assert.Equal(t, "issuer", oidc.Issuer)
+ assert.Equal(t, "clientID", oidc.ClientID)
+ assert.Equal(t, []string{"scope"}, oidc.Scopes)
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *oidc.StylingType)
+ assert.Equal(t, false, oidc.AutoRegister)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.IDPDisplayNameMapping)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL), oidc.UserNameMapping)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp oidc changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check original values for OCID
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.IdpId), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addOIDC.IdpId, oidc.ID)
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = MgmtClient.UpdateOrgIDPOIDCConfig(IAMCTX, &management.UpdateOrgIDPOIDCConfigRequest{
+ IdpId: addOIDC.IdpId,
+ ClientId: "new_clientID",
+ ClientSecret: "new_clientSecret",
+ Issuer: "new_issuer",
+ Scopes: []string{"new_scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOIDC, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oidc.config.changed
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Equal(t, orgID, *oidc.OrgID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, addOIDC.IdpId, updateOIDC.ID)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*updateOIDC.Type))
+ assert.WithinRange(t, updateOIDC.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Equal(t, orgID, *oidc.OrgID)
+ assert.Equal(t, "new_issuer", updateOIDC.Issuer)
+ assert.Equal(t, "new_clientID", updateOIDC.ClientID)
+ assert.NotNil(t, oidc.ClientSecret)
+ assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.IDPDisplayNameMapping)
+ assert.Equal(t, domain.OIDCMappingField(idp.OIDCMappingField_OIDC_MAPPING_FIELD_PREFERRED_USERNAME), updateOIDC.UserNameMapping)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp jwt added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := MgmtClient.AddOrgJWTIDP(IAMCTX, &management.AddOrgJWTIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ JwtEndpoint: "jwtEndpoint",
+ Issuer: "issuer",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ jwt, err := idpRepo.GetJWT(IAMCTX, pool,
+ idpRepo.IDCondition(addJWT.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.jwt.config.added
+ // idp
+ assert.Equal(t, instanceID, jwt.InstanceID)
+ assert.Equal(t, orgID, *jwt.OrgID)
+ assert.Equal(t, name, jwt.Name)
+ assert.Equal(t, addJWT.IdpId, jwt.ID)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*jwt.Type))
+ assert.Equal(t, int16(idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE), *jwt.StylingType)
+
+ // jwt
+ assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint)
+ assert.Equal(t, "issuer", jwt.Issuer)
+ assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint)
+ assert.Equal(t, "headerName", jwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test iam idp jwt changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := MgmtClient.AddOrgJWTIDP(IAMCTX, &management.AddOrgJWTIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ JwtEndpoint: "jwtEndpoint",
+ Issuer: "issuer",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ before := time.Now()
+ _, err = MgmtClient.UpdateOrgIDPJWTConfig(IAMCTX, &management.UpdateOrgIDPJWTConfigRequest{
+ IdpId: addJWT.IdpId,
+ JwtEndpoint: "new_jwtEndpoint",
+ Issuer: "new_issuer",
+ KeysEndpoint: "new_keyEndpoint",
+ HeaderName: "new_headerName",
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateJWT, err := idpRepo.GetJWT(IAMCTX, pool,
+ idpRepo.IDCondition(addJWT.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.jwt.config.changed
+ // idp
+ assert.Equal(t, addJWT.IdpId, updateJWT.ID)
+ assert.Equal(t, orgID, *updateJWT.OrgID)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*updateJWT.Type))
+ assert.WithinRange(t, updateJWT.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "new_jwtEndpoint", updateJWT.JWTEndpoint)
+ assert.Equal(t, "new_issuer", updateJWT.Issuer)
+ assert.Equal(t, "new_keyEndpoint", updateJWT.KeysEndpoint)
+ assert.Equal(t, "new_headerName", updateJWT.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp oauth added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oauth
+ before := time.Now()
+ addOAuth, err := MgmtClient.AddGenericOAuthProvider(IAMCTX, &management.AddGenericOAuthProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authoizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ IdAttribute: "idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ UsePkce: false,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oauth
+ var oauth *domain.IDPOAuth
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oauth, err = idpRepo.GetOAuth(IAMCTX, pool, idpRepo.IDCondition(addOAuth.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.oauth.added
+ // idp
+ assert.Equal(t, instanceID, oauth.InstanceID)
+ assert.Equal(t, orgID, *oauth.OrgID)
+ assert.Equal(t, addOAuth.Id, oauth.ID)
+ assert.Equal(t, name, oauth.Name)
+ assert.Equal(t, domain.IDPTypeOAuth, domain.IDPType(*oauth.Type))
+ assert.Equal(t, false, oauth.AllowLinking)
+ assert.Equal(t, false, oauth.AllowCreation)
+ assert.Equal(t, false, oauth.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*oauth.AutoLinkingField))
+ assert.WithinRange(t, oauth.CreatedAt, before, after)
+ assert.WithinRange(t, oauth.UpdatedAt, before, after)
+
+ // oauth
+ assert.Equal(t, "clientId", oauth.ClientID)
+ assert.NotNil(t, oauth.ClientSecret)
+ assert.Equal(t, "authoizationEndpoint", oauth.AuthorizationEndpoint)
+ assert.Equal(t, "tokenEndpoint", oauth.TokenEndpoint)
+ assert.Equal(t, "userEndpoint", oauth.UserEndpoint)
+ assert.Equal(t, []string{"scope"}, oauth.Scopes)
+ assert.Equal(t, "idAttribute", oauth.IDAttribute)
+ assert.Equal(t, false, oauth.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp oauth changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oauth
+ addOAuth, err := MgmtClient.AddGenericOAuthProvider(IAMCTX, &management.AddGenericOAuthProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authoizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ IdAttribute: "idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oauth
+ var oauth *domain.IDPOAuth
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oauth, err = idpRepo.GetOAuth(IAMCTX, pool, idpRepo.IDCondition(addOAuth.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addOAuth.Id, oauth.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ before := time.Now()
+ _, err = MgmtClient.UpdateGenericOAuthProvider(IAMCTX, &management.UpdateGenericOAuthProviderRequest{
+ Id: addOAuth.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ AuthorizationEndpoint: "new_authoizationEndpoint",
+ TokenEndpoint: "new_tokenEndpoint",
+ UserEndpoint: "new_userEndpoint",
+ Scopes: []string{"new_scope"},
+ IdAttribute: "new_idAttribute",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ UsePkce: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOauth, err := idpRepo.GetOAuth(IAMCTX, pool,
+ idpRepo.IDCondition(addOAuth.Id),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oauth.changed
+ // idp
+ assert.Equal(t, instanceID, updateOauth.InstanceID)
+ assert.Equal(t, orgID, *updateOauth.OrgID)
+ assert.Equal(t, addOAuth.Id, updateOauth.ID)
+ assert.Equal(t, name, updateOauth.Name)
+ assert.Equal(t, domain.IDPTypeOAuth, domain.IDPType(*updateOauth.Type))
+ assert.Equal(t, true, updateOauth.AllowLinking)
+ assert.Equal(t, true, updateOauth.AllowCreation)
+ assert.Equal(t, true, updateOauth.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateOauth.AutoLinkingField))
+ assert.Equal(t, true, updateOauth.UsePKCE)
+ assert.WithinRange(t, updateOauth.UpdatedAt, before, after)
+
+ // oauth
+ assert.Equal(t, "new_clientId", updateOauth.ClientID)
+ assert.NotEqual(t, oauth.ClientSecret, updateOauth.ClientSecret)
+ assert.Equal(t, "new_authoizationEndpoint", updateOauth.AuthorizationEndpoint)
+ assert.Equal(t, "new_tokenEndpoint", updateOauth.TokenEndpoint)
+ assert.Equal(t, "new_userEndpoint", updateOauth.UserEndpoint)
+ assert.Equal(t, []string{"new_scope"}, updateOauth.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp oidc added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add oidc
+ before := time.Now()
+ addOIDC, err := MgmtClient.AddGenericOIDCProvider(IAMCTX, &management.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oidc
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err := idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.oidc added
+ // idp
+ assert.Equal(t, instanceID, oidc.InstanceID)
+ assert.Equal(t, orgID, *oidc.OrgID)
+ assert.Equal(t, addOIDC.Id, oidc.ID)
+ assert.Equal(t, name, oidc.Name)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ assert.Equal(t, false, oidc.AllowLinking)
+ assert.Equal(t, false, oidc.AllowCreation)
+ assert.Equal(t, false, oidc.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*oidc.AutoLinkingField))
+ assert.WithinRange(t, oidc.CreatedAt, before, after)
+ assert.WithinRange(t, oidc.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, addOIDC.Id, oidc.ID)
+ assert.Equal(t, "clientId", oidc.ClientID)
+ assert.NotNil(t, oidc.ClientSecret)
+ assert.Equal(t, []string{"scope"}, oidc.Scopes)
+ assert.Equal(t, "issuer", oidc.Issuer)
+ assert.Equal(t, false, oidc.IsIDTokenMapping)
+ assert.Equal(t, false, oidc.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test instanceidp oidc changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ addOIDC, err := MgmtClient.AddGenericOIDCProvider(IAMCTX, &management.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for oidc
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ before := time.Now()
+ _, err = MgmtClient.UpdateGenericOIDCProvider(IAMCTX, &management.UpdateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Name: name,
+ Issuer: "new_issuer",
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ IsIdTokenMapping: true,
+ UsePkce: true,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateOIDC, err := idpRepo.GetOIDC(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.Id),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+
+ // event org.idp.oidc.changed
+ // idp
+ assert.Equal(t, instanceID, updateOIDC.InstanceID)
+ assert.Equal(t, orgID, *updateOIDC.OrgID)
+ assert.Equal(t, addOIDC.Id, updateOIDC.ID)
+ assert.Equal(t, name, updateOIDC.Name)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*updateOIDC.Type))
+ assert.Equal(t, true, updateOIDC.AllowLinking)
+ assert.Equal(t, true, updateOIDC.AllowCreation)
+ assert.Equal(t, true, updateOIDC.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateOIDC.AutoLinkingField))
+ assert.WithinRange(t, updateOIDC.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, "new_clientId", updateOIDC.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, updateOIDC.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateOIDC.Scopes)
+ assert.Equal(t, true, updateOIDC.IsIDTokenMapping)
+ assert.Equal(t, true, updateOIDC.UsePKCE)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp oidc migrated azure migration reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // create OIDC
+ addOIDC, err := MgmtClient.AddGenericOIDCProvider(IAMCTX, &management.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = MgmtClient.MigrateGenericOIDCProvider(IAMCTX, &management.MigrateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Template: &management.MigrateGenericOIDCProviderRequest_Azure{
+ Azure: &management.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ },
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.oidc.migrated.azure
+ // idp
+ assert.Equal(t, instanceID, azure.InstanceID)
+ assert.Equal(t, orgID, *azure.OrgID)
+ assert.Equal(t, addOIDC.Id, azure.ID)
+ assert.Equal(t, name, azure.Name)
+ // type = azure
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*azure.Type))
+ assert.Equal(t, true, azure.AllowLinking)
+ assert.Equal(t, true, azure.AllowCreation)
+ assert.Equal(t, true, azure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*azure.AutoLinkingField))
+ assert.WithinRange(t, azure.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, "new_clientId", azure.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, azure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeOrganizations, azure.Tenant)
+ assert.Equal(t, true, azure.IsEmailVerified)
+ assert.Equal(t, []string{"new_scope"}, azure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp oidc migrated google migration reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // create OIDC
+ addOIDC, err := MgmtClient.AddGenericOIDCProvider(IAMCTX, &management.AddGenericOIDCProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ Issuer: "issuer",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ IsIdTokenMapping: false,
+ UsePkce: false,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var oidc *domain.IDPOIDC
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ oidc, err = idpRepo.GetOIDC(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, domain.IDPTypeOIDC, domain.IDPType(*oidc.Type))
+ }, retryDuration, tick)
+
+ before := time.Now()
+ _, err = MgmtClient.MigrateGenericOIDCProvider(IAMCTX, &management.MigrateGenericOIDCProviderRequest{
+ Id: addOIDC.Id,
+ Template: &management.MigrateGenericOIDCProviderRequest_Google{
+ Google: &management.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ },
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addOIDC.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.oidc.migrated.google
+ // idp
+ assert.Equal(t, instanceID, google.InstanceID)
+ assert.Equal(t, orgID, *google.OrgID)
+ assert.Equal(t, addOIDC.Id, google.ID)
+ assert.Equal(t, name, google.Name)
+ // type = google
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*google.Type))
+ assert.Equal(t, true, google.AllowLinking)
+ assert.Equal(t, true, google.AllowCreation)
+ assert.Equal(t, true, google.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*google.AutoLinkingField))
+ assert.WithinRange(t, google.UpdatedAt, before, after)
+
+ // oidc
+ assert.Equal(t, "new_clientId", google.ClientID)
+ assert.NotEqual(t, oidc.ClientSecret, google.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, google.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp jwt added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ before := time.Now()
+ addJWT, err := MgmtClient.AddJWTProvider(IAMCTX, &management.AddJWTProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ JwtEndpoint: "jwtEndpoint",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for jwt
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ jwt, err := idpRepo.GetJWT(IAMCTX, pool, idpRepo.IDCondition(addJWT.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.jwt.added
+ // idp
+ assert.Equal(t, instanceID, jwt.InstanceID)
+ assert.Equal(t, orgID, *jwt.OrgID)
+ assert.Equal(t, addJWT.Id, jwt.ID)
+ assert.Equal(t, name, jwt.Name)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*jwt.Type))
+ assert.Equal(t, false, jwt.AllowLinking)
+ assert.Equal(t, false, jwt.AllowCreation)
+ assert.Equal(t, false, jwt.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*jwt.AutoLinkingField))
+ assert.WithinRange(t, jwt.CreatedAt, before, after)
+ assert.WithinRange(t, jwt.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "jwtEndpoint", jwt.JWTEndpoint)
+ assert.Equal(t, "issuer", jwt.Issuer)
+ assert.Equal(t, "keyEndpoint", jwt.KeysEndpoint)
+ assert.Equal(t, "headerName", jwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp jwt changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add jwt
+ addJWT, err := MgmtClient.AddJWTProvider(IAMCTX, &management.AddJWTProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ JwtEndpoint: "jwtEndpoint",
+ KeysEndpoint: "keyEndpoint",
+ HeaderName: "headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ require.NoError(t, err)
+
+ name = "new_" + name
+ // change jwt
+ before := time.Now()
+ _, err = MgmtClient.UpdateJWTProvider(IAMCTX, &management.UpdateJWTProviderRequest{
+ Id: addJWT.Id,
+ Name: name,
+ Issuer: "new_issuer",
+ JwtEndpoint: "new_jwtEndpoint",
+ KeysEndpoint: "new_keyEndpoint",
+ HeaderName: "new_headerName",
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for jwt
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateJwt, err := idpRepo.GetJWT(IAMCTX, pool, idpRepo.IDCondition(addJWT.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.jwt.added
+ // idp
+ assert.Equal(t, instanceID, updateJwt.InstanceID)
+ assert.Equal(t, orgID, *updateJwt.OrgID)
+ assert.Equal(t, addJWT.Id, updateJwt.ID)
+ assert.Equal(t, name, updateJwt.Name)
+ assert.Equal(t, domain.IDPTypeJWT, domain.IDPType(*updateJwt.Type))
+ assert.Equal(t, true, updateJwt.AllowLinking)
+ assert.Equal(t, true, updateJwt.AllowCreation)
+ assert.Equal(t, true, updateJwt.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateJwt.AutoLinkingField))
+ assert.WithinRange(t, updateJwt.UpdatedAt, before, after)
+
+ // jwt
+ assert.Equal(t, "new_jwtEndpoint", updateJwt.JWTEndpoint)
+ assert.Equal(t, "new_issuer", updateJwt.Issuer)
+ assert.Equal(t, "new_keyEndpoint", updateJwt.KeysEndpoint)
+ assert.Equal(t, "new_headerName", updateJwt.HeaderName)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp azure added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add azure
+ before := time.Now()
+ addAzure, err := MgmtClient.AddAzureADProvider(IAMCTX, &management.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for azure
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.azure.added
+ // idp
+ assert.Equal(t, instanceID, azure.InstanceID)
+ assert.Equal(t, orgID, *azure.OrgID)
+ assert.Equal(t, addAzure.Id, azure.ID)
+ assert.Equal(t, name, azure.Name)
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*azure.Type))
+ assert.Equal(t, true, azure.AllowLinking)
+ assert.Equal(t, true, azure.AllowCreation)
+ assert.Equal(t, true, azure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*azure.AutoLinkingField))
+ assert.WithinRange(t, azure.UpdatedAt, before, after)
+
+ // azure
+ assert.Equal(t, "clientId", azure.ClientID)
+ assert.NotNil(t, azure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeOrganizations, azure.Tenant)
+ assert.Equal(t, true, azure.IsEmailVerified)
+ assert.Equal(t, []string{"scope"}, azure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp azure changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add azure
+ addAzure, err := MgmtClient.AddAzureADProvider(IAMCTX, &management.AddAzureADProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS,
+ },
+ },
+ EmailVerified: false,
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var azure *domain.IDPAzureAD
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ azure, err = idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addAzure.Id, azure.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change azure
+ before := time.Now()
+ _, err = MgmtClient.UpdateAzureADProvider(IAMCTX, &management.UpdateAzureADProviderRequest{
+ Id: addAzure.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Tenant: &idp_grpc.AzureADTenant{
+ Type: &idp_grpc.AzureADTenant_TenantType{
+ TenantType: idp.AzureADTenantType_AZURE_AD_TENANT_TYPE_CONSUMERS,
+ },
+ },
+ EmailVerified: true,
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateAzure, err := idpRepo.GetAzureAD(IAMCTX, pool, idpRepo.IDCondition(addAzure.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.azure.changed
+ // idp
+ assert.Equal(t, instanceID, updateAzure.InstanceID)
+ assert.Equal(t, orgID, *updateAzure.OrgID)
+ assert.Equal(t, addAzure.Id, updateAzure.ID)
+ assert.Equal(t, name, updateAzure.Name)
+ assert.Equal(t, domain.IDPTypeAzure, domain.IDPType(*updateAzure.Type))
+ assert.Equal(t, true, updateAzure.AllowLinking)
+ assert.Equal(t, true, updateAzure.AllowCreation)
+ assert.Equal(t, true, updateAzure.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*updateAzure.AutoLinkingField))
+ assert.WithinRange(t, updateAzure.UpdatedAt, before, after)
+
+ // azure
+ assert.Equal(t, "new_clientId", updateAzure.ClientID)
+ assert.NotEqual(t, azure.ClientSecret, updateAzure.ClientSecret)
+ assert.Equal(t, domain.AzureTenantTypeConsumers, updateAzure.Tenant)
+ assert.Equal(t, true, updateAzure.IsEmailVerified)
+ assert.Equal(t, []string{"new_scope"}, updateAzure.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp github added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github
+ before := time.Now()
+ addGithub, err := MgmtClient.AddGitHubProvider(IAMCTX, &management.AddGitHubProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for github
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ github, err := idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.github.added
+ // idp
+ assert.Equal(t, instanceID, github.InstanceID)
+ assert.Equal(t, orgID, *github.OrgID)
+ assert.Equal(t, addGithub.Id, github.ID)
+ assert.Equal(t, name, github.Name)
+ assert.Equal(t, domain.IDPTypeGitHub, domain.IDPType(*github.Type))
+ assert.Equal(t, false, github.AllowLinking)
+ assert.Equal(t, false, github.AllowCreation)
+ assert.Equal(t, false, github.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*github.AutoLinkingField))
+ assert.WithinRange(t, github.UpdatedAt, before, after)
+
+ assert.Equal(t, "clientId", github.ClientID)
+ assert.NotNil(t, github.ClientSecret)
+ assert.Equal(t, []string{"scope"}, github.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp github changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github
+ addGithub, err := MgmtClient.AddGitHubProvider(IAMCTX, &management.AddGitHubProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var github *domain.IDPGithub
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ github, err = idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addGithub.Id, github.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change github
+ before := time.Now()
+ _, err = MgmtClient.UpdateGitHubProvider(IAMCTX, &management.UpdateGitHubProviderRequest{
+ Id: addGithub.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGithub, err := idpRepo.GetGithub(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.github.changed
+ // idp
+ assert.Equal(t, instanceID, updateGithub.InstanceID)
+ assert.Equal(t, orgID, *updateGithub.OrgID)
+ assert.Equal(t, addGithub.Id, updateGithub.ID)
+ assert.Equal(t, name, updateGithub.Name)
+ assert.Equal(t, domain.IDPTypeGitHub, domain.IDPType(*updateGithub.Type))
+ assert.Equal(t, true, updateGithub.AllowLinking)
+ assert.Equal(t, true, updateGithub.AllowCreation)
+ assert.Equal(t, true, updateGithub.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGithub.AutoLinkingField))
+ assert.WithinRange(t, updateGithub.UpdatedAt, before, after)
+
+ // github
+ assert.Equal(t, "new_clientId", updateGithub.ClientID)
+ assert.NotEqual(t, github.ClientSecret, updateGithub.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGithub.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp github enterprise added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github enterprise
+ before := time.Now()
+ addGithubEnterprise, err := MgmtClient.AddGitHubEnterpriseServerProvider(IAMCTX, &management.AddGitHubEnterpriseServerProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authoizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for github enterprise
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githubEnterprise, err := idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.github_enterprise.added
+ // idp
+ assert.Equal(t, instanceID, githubEnterprise.InstanceID)
+ assert.Equal(t, orgID, *githubEnterprise.OrgID)
+ assert.Equal(t, addGithubEnterprise.Id, githubEnterprise.ID)
+ assert.Equal(t, name, githubEnterprise.Name)
+ assert.Equal(t, domain.IDPTypeGitHubEnterprise, domain.IDPType(*githubEnterprise.Type))
+ assert.Equal(t, false, githubEnterprise.AllowLinking)
+ assert.Equal(t, false, githubEnterprise.AllowCreation)
+ assert.Equal(t, false, githubEnterprise.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*githubEnterprise.AutoLinkingField))
+ assert.WithinRange(t, githubEnterprise.CreatedAt, before, after)
+ assert.WithinRange(t, githubEnterprise.UpdatedAt, before, after)
+
+ // github enterprise
+ assert.Equal(t, "clientId", githubEnterprise.ClientID)
+ assert.NotNil(t, githubEnterprise.ClientSecret)
+ assert.Equal(t, "authoizationEndpoint", githubEnterprise.AuthorizationEndpoint)
+ assert.Equal(t, "tokenEndpoint", githubEnterprise.TokenEndpoint)
+ assert.Equal(t, "userEndpoint", githubEnterprise.UserEndpoint)
+ assert.Equal(t, []string{"scope"}, githubEnterprise.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp github enterprise changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add github enterprise
+ addGithubEnterprise, err := MgmtClient.AddGitHubEnterpriseServerProvider(IAMCTX, &management.AddGitHubEnterpriseServerProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ AuthorizationEndpoint: "authoizationEndpoint",
+ TokenEndpoint: "tokenEndpoint",
+ UserEndpoint: "userEndpoint",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var githubEnterprise *domain.IDPGithubEnterprise
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githubEnterprise, err = idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addGithubEnterprise.Id, githubEnterprise.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change github enterprise
+ before := time.Now()
+ _, err = MgmtClient.UpdateGitHubEnterpriseServerProvider(IAMCTX, &management.UpdateGitHubEnterpriseServerProviderRequest{
+ Id: addGithubEnterprise.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ AuthorizationEndpoint: "new_authoizationEndpoint",
+ TokenEndpoint: "new_tokenEndpoint",
+ UserEndpoint: "new_userEndpoint",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for azure
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGithubEnterprise, err := idpRepo.GetGithubEnterprise(IAMCTX, pool, idpRepo.IDCondition(addGithubEnterprise.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.github_enterprise.changed
+ // idp
+ assert.Equal(t, instanceID, githubEnterprise.InstanceID)
+ assert.Equal(t, orgID, *githubEnterprise.OrgID)
+ assert.Equal(t, addGithubEnterprise.Id, updateGithubEnterprise.ID)
+ assert.Equal(t, name, updateGithubEnterprise.Name)
+ assert.Equal(t, domain.IDPTypeGitHubEnterprise, domain.IDPType(*updateGithubEnterprise.Type))
+ assert.Equal(t, false, updateGithubEnterprise.AllowLinking)
+ assert.Equal(t, false, updateGithubEnterprise.AllowCreation)
+ assert.Equal(t, false, updateGithubEnterprise.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*updateGithubEnterprise.AutoLinkingField))
+ assert.WithinRange(t, updateGithubEnterprise.UpdatedAt, before, after)
+
+ // github enterprise
+ assert.Equal(t, "new_clientId", updateGithubEnterprise.ClientID)
+ assert.NotNil(t, updateGithubEnterprise.ClientSecret)
+ assert.Equal(t, "new_authoizationEndpoint", updateGithubEnterprise.AuthorizationEndpoint)
+ assert.Equal(t, "new_tokenEndpoint", updateGithubEnterprise.TokenEndpoint)
+ assert.Equal(t, "new_userEndpoint", updateGithubEnterprise.UserEndpoint)
+ assert.Equal(t, []string{"new_scope"}, updateGithubEnterprise.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp gitlab added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab
+ before := time.Now()
+ addGithub, err := MgmtClient.AddGitLabProvider(IAMCTX, &management.AddGitLabProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for gitlab
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ gitlab, err := idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGithub.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.gitlab.added
+ // idp
+ assert.Equal(t, instanceID, gitlab.InstanceID)
+ assert.Equal(t, orgID, *gitlab.OrgID)
+ assert.Equal(t, addGithub.Id, gitlab.ID)
+ assert.Equal(t, name, gitlab.Name)
+ assert.Equal(t, domain.IDPTypeGitLab, domain.IDPType(*gitlab.Type))
+ assert.Equal(t, false, gitlab.AllowLinking)
+ assert.Equal(t, false, gitlab.AllowCreation)
+ assert.Equal(t, false, gitlab.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*gitlab.AutoLinkingField))
+ assert.WithinRange(t, gitlab.CreatedAt, before, after)
+ assert.WithinRange(t, gitlab.UpdatedAt, before, after)
+
+ // gitlab
+ assert.Equal(t, "clientId", gitlab.ClientID)
+ assert.NotNil(t, gitlab.ClientSecret)
+ assert.Equal(t, []string{"scope"}, gitlab.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp gitlab changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab
+ addGitlab, err := MgmtClient.AddGitLabProvider(IAMCTX, &management.AddGitLabProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var gitlab *domain.IDPGitlab
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ gitlab, err = idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGitlab.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addGitlab.Id, gitlab.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change gitlab
+ before := time.Now()
+ _, err = MgmtClient.UpdateGitLabProvider(IAMCTX, &management.UpdateGitLabProviderRequest{
+ Id: addGitlab.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for gitlab
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGitlab, err := idpRepo.GetGitlab(IAMCTX, pool, idpRepo.IDCondition(addGitlab.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.gitlab.changed
+ // idp
+ assert.Equal(t, instanceID, updateGitlab.InstanceID)
+ assert.Equal(t, orgID, *updateGitlab.OrgID)
+ assert.Equal(t, addGitlab.Id, updateGitlab.ID)
+ assert.Equal(t, name, updateGitlab.Name)
+ assert.Equal(t, true, updateGitlab.AllowLinking)
+ assert.Equal(t, true, updateGitlab.AllowCreation)
+ assert.Equal(t, true, updateGitlab.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGitlab.AutoLinkingField))
+ assert.WithinRange(t, updateGitlab.UpdatedAt, before, after)
+
+ // gitlab
+ assert.Equal(t, "new_clientId", updateGitlab.ClientID)
+ assert.NotEqual(t, gitlab.ClientSecret, updateGitlab.ClientSecret)
+ assert.Equal(t, domain.IDPTypeGitLab, domain.IDPType(*updateGitlab.Type))
+ assert.Equal(t, []string{"new_scope"}, updateGitlab.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp gitlab self hosted added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab self hosted
+ before := time.Now()
+ addGitlabSelfHosted, err := MgmtClient.AddGitLabSelfHostedProvider(IAMCTX, &management.AddGitLabSelfHostedProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for gitlab self hosted
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ gitlabSelfHosted, err := idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.gitlab_self_hosted.added
+ // idp
+ assert.Equal(t, instanceID, gitlabSelfHosted.InstanceID)
+ assert.Equal(t, orgID, *gitlabSelfHosted.OrgID)
+ assert.Equal(t, addGitlabSelfHosted.Id, gitlabSelfHosted.ID)
+ assert.Equal(t, name, gitlabSelfHosted.Name)
+ assert.Equal(t, domain.IDPTypeGitLabSelfHosted, domain.IDPType(*gitlabSelfHosted.Type))
+ assert.Equal(t, false, gitlabSelfHosted.AllowLinking)
+ assert.Equal(t, false, gitlabSelfHosted.AllowCreation)
+ assert.Equal(t, false, gitlabSelfHosted.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*gitlabSelfHosted.AutoLinkingField))
+ assert.WithinRange(t, gitlabSelfHosted.CreatedAt, before, after)
+ assert.WithinRange(t, gitlabSelfHosted.UpdatedAt, before, after)
+
+ // gitlab self hosted
+ assert.Equal(t, "clientId", gitlabSelfHosted.ClientID)
+ assert.Equal(t, "issuer", gitlabSelfHosted.Issuer)
+ assert.NotNil(t, gitlabSelfHosted.ClientSecret)
+ assert.Equal(t, []string{"scope"}, gitlabSelfHosted.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp gitlab self hosted changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add gitlab self hosted
+ addGitlabSelfHosted, err := MgmtClient.AddGitLabSelfHostedProvider(IAMCTX, &management.AddGitLabSelfHostedProviderRequest{
+ Name: name,
+ Issuer: "issuer",
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ 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()
+
+ var githlabSelfHosted *domain.IDPGitlabSelfHosting
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ githlabSelfHosted, err = idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addGitlabSelfHosted.Id, githlabSelfHosted.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change gitlab self hosted
+ before := time.Now()
+ _, err = MgmtClient.UpdateGitLabSelfHostedProvider(IAMCTX, &management.UpdateGitLabSelfHostedProviderRequest{
+ Id: addGitlabSelfHosted.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ Issuer: "new_issuer",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for gitlab self hosted
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGitlabSelfHosted, err := idpRepo.GetGitlabSelfHosting(IAMCTX, pool, idpRepo.IDCondition(addGitlabSelfHosted.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.gitlab_self_hosted.changed
+ // idp
+ assert.Equal(t, instanceID, updateGitlabSelfHosted.InstanceID)
+ assert.Equal(t, orgID, *updateGitlabSelfHosted.OrgID)
+ assert.Equal(t, addGitlabSelfHosted.Id, updateGitlabSelfHosted.ID)
+ assert.Equal(t, name, updateGitlabSelfHosted.Name)
+ assert.Equal(t, domain.IDPTypeGitLabSelfHosted, domain.IDPType(*updateGitlabSelfHosted.Type))
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowLinking)
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowCreation)
+ assert.Equal(t, true, updateGitlabSelfHosted.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGitlabSelfHosted.AutoLinkingField))
+ assert.WithinRange(t, updateGitlabSelfHosted.UpdatedAt, before, after)
+
+ // gitlab self hosted
+ assert.Equal(t, "new_clientId", updateGitlabSelfHosted.ClientID)
+ assert.Equal(t, "new_issuer", updateGitlabSelfHosted.Issuer)
+ assert.NotEqual(t, githlabSelfHosted.ClientSecret, updateGitlabSelfHosted.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGitlabSelfHosted.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp google added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add google
+ before := time.Now()
+ addGoogle, err := MgmtClient.AddGoogleProvider(IAMCTX, &management.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ Scopes: []string{"scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check values for google
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.google.added
+ // idp
+ assert.Equal(t, instanceID, google.InstanceID)
+ assert.Equal(t, orgID, *google.OrgID)
+ assert.Equal(t, addGoogle.Id, google.ID)
+ assert.Equal(t, name, google.Name)
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*google.Type))
+ assert.Equal(t, false, google.AllowLinking)
+ assert.Equal(t, false, google.AllowCreation)
+ assert.Equal(t, false, google.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*google.AutoLinkingField))
+ assert.WithinRange(t, google.CreatedAt, before, after)
+ assert.WithinRange(t, google.UpdatedAt, before, after)
+
+ // google
+ assert.Equal(t, "clientId", google.ClientID)
+ assert.NotNil(t, google.ClientSecret)
+ assert.Equal(t, []string{"scope"}, google.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org idp google changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add google
+ addGoogle, err := MgmtClient.AddGoogleProvider(IAMCTX, &management.AddGoogleProviderRequest{
+ Name: name,
+ ClientId: "clientId",
+ ClientSecret: "clientSecret",
+ 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()
+
+ var google *domain.IDPGoogle
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ google, err = idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addGoogle.Id, google.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change google
+ before := time.Now()
+ _, err = MgmtClient.UpdateGoogleProvider(IAMCTX, &management.UpdateGoogleProviderRequest{
+ Id: addGoogle.Id,
+ Name: name,
+ ClientId: "new_clientId",
+ ClientSecret: "new_clientSecret",
+ Scopes: []string{"new_scope"},
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for google
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateGoogle, err := idpRepo.GetGoogle(IAMCTX, pool, idpRepo.IDCondition(addGoogle.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.google.changed
+ // idp
+ assert.Equal(t, instanceID, updateGoogle.InstanceID)
+ assert.Equal(t, orgID, *updateGoogle.OrgID)
+ assert.Equal(t, addGoogle.Id, updateGoogle.ID)
+ assert.Equal(t, name, updateGoogle.Name)
+ assert.Equal(t, domain.IDPTypeGoogle, domain.IDPType(*updateGoogle.Type))
+ assert.Equal(t, true, updateGoogle.AllowLinking)
+ assert.Equal(t, true, updateGoogle.AllowCreation)
+ assert.Equal(t, true, updateGoogle.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateGoogle.AutoLinkingField))
+ assert.WithinRange(t, updateGoogle.UpdatedAt, before, after)
+
+ // google
+ assert.Equal(t, "new_clientId", updateGoogle.ClientID)
+ assert.NotEqual(t, google.ClientSecret, updateGoogle.ClientSecret)
+ assert.Equal(t, []string{"new_scope"}, updateGoogle.Scopes)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org ldap added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add ldap
+ before := time.Now()
+ addLdap, err := MgmtClient.AddLDAPProvider(IAMCTX, &management.AddLDAPProviderRequest{
+ Name: name,
+ Servers: []string{"servers"},
+ StartTls: true,
+ BaseDn: "baseDN",
+ BindDn: "bindND",
+ BindPassword: "bindPassword",
+ UserBase: "userBase",
+ UserObjectClasses: []string{"userOhjectClasses"},
+ UserFilters: []string{"userFilters"},
+ Timeout: durationpb.New(time.Minute),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "idAttribute",
+ FirstNameAttribute: "firstNameAttribute",
+ LastNameAttribute: "lastNameAttribute",
+ DisplayNameAttribute: "displayNameAttribute",
+ NickNameAttribute: "nickNameAttribute",
+ PreferredUsernameAttribute: "preferredUsernameAttribute",
+ EmailAttribute: "emailAttribute",
+ EmailVerifiedAttribute: "emailVerifiedAttribute",
+ PhoneAttribute: "phoneAttribute",
+ PhoneVerifiedAttribute: "phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "preferredLanguageAttribute",
+ AvatarUrlAttribute: "avatarUrlAttribute",
+ ProfileAttribute: "profileAttribute",
+ },
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: false,
+ IsCreationAllowed: false,
+ IsAutoCreation: false,
+ IsAutoUpdate: false,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ ldap, err := idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.ldap.v2.added
+ // idp
+ assert.Equal(t, instanceID, ldap.InstanceID)
+ assert.Equal(t, orgID, *ldap.OrgID)
+ assert.Equal(t, addLdap.Id, ldap.ID)
+ assert.Equal(t, name, ldap.Name)
+ assert.Equal(t, domain.IDPTypeLDAP, domain.IDPType(*ldap.Type))
+ assert.Equal(t, false, ldap.AllowLinking)
+ assert.Equal(t, false, ldap.AllowCreation)
+ assert.Equal(t, false, ldap.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*ldap.AutoLinkingField))
+ assert.WithinRange(t, ldap.CreatedAt, before, after)
+ assert.WithinRange(t, ldap.UpdatedAt, before, after)
+
+ // ldap
+ assert.Equal(t, []string{"servers"}, ldap.Servers)
+ assert.Equal(t, true, ldap.StartTLS)
+ assert.Equal(t, "baseDN", ldap.BaseDN)
+ assert.Equal(t, "bindND", ldap.BindDN)
+ assert.NotNil(t, ldap.BindPassword)
+ assert.Equal(t, "userBase", ldap.UserBase)
+ assert.Equal(t, []string{"userOhjectClasses"}, ldap.UserObjectClasses)
+ assert.Equal(t, []string{"userFilters"}, ldap.UserFilters)
+ assert.Equal(t, time.Minute, ldap.Timeout)
+ assert.Equal(t, "idAttribute", ldap.IDAttribute)
+ assert.Equal(t, "firstNameAttribute", ldap.FirstNameAttribute)
+ assert.Equal(t, "lastNameAttribute", ldap.LastNameAttribute)
+ assert.Equal(t, "displayNameAttribute", ldap.DisplayNameAttribute)
+ assert.Equal(t, "nickNameAttribute", ldap.NickNameAttribute)
+ assert.Equal(t, "preferredUsernameAttribute", ldap.PreferredUsernameAttribute)
+ assert.Equal(t, "emailAttribute", ldap.EmailAttribute)
+ assert.Equal(t, "emailVerifiedAttribute", ldap.EmailVerifiedAttribute)
+ assert.Equal(t, "phoneAttribute", ldap.PhoneAttribute)
+ assert.Equal(t, "phoneVerifiedAttribute", ldap.PhoneVerifiedAttribute)
+ assert.Equal(t, "preferredLanguageAttribute", ldap.PreferredLanguageAttribute)
+ assert.Equal(t, "avatarUrlAttribute", ldap.AvatarURLAttribute)
+ assert.Equal(t, "profileAttribute", ldap.ProfileAttribute)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org ldap changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add ldap
+ addLdap, err := MgmtClient.AddLDAPProvider(IAMCTX, &management.AddLDAPProviderRequest{
+ Name: name,
+ Servers: []string{"servers"},
+ StartTls: true,
+ BaseDn: "baseDN",
+ BindDn: "bindND",
+ BindPassword: "bindPassword",
+ UserBase: "userBase",
+ UserObjectClasses: []string{"userOhjectClasses"},
+ UserFilters: []string{"userFilters"},
+ Timeout: durationpb.New(time.Minute),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "idAttribute",
+ FirstNameAttribute: "firstNameAttribute",
+ LastNameAttribute: "lastNameAttribute",
+ DisplayNameAttribute: "displayNameAttribute",
+ NickNameAttribute: "nickNameAttribute",
+ PreferredUsernameAttribute: "preferredUsernameAttribute",
+ EmailAttribute: "emailAttribute",
+ EmailVerifiedAttribute: "emailVerifiedAttribute",
+ PhoneAttribute: "phoneAttribute",
+ PhoneVerifiedAttribute: "phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "preferredLanguageAttribute",
+ AvatarUrlAttribute: "avatarUrlAttribute",
+ ProfileAttribute: "profileAttribute",
+ },
+ 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()
+
+ var ldap *domain.IDPLDAP
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ ldap, err = idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addLdap.Id, ldap.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change ldap
+ before := time.Now()
+ _, err = MgmtClient.UpdateLDAPProvider(IAMCTX, &management.UpdateLDAPProviderRequest{
+ Id: addLdap.Id,
+ Name: name,
+ Servers: []string{"new_servers"},
+ StartTls: false,
+ BaseDn: "new_baseDN",
+ BindDn: "new_bindND",
+ BindPassword: "new_bindPassword",
+ UserBase: "new_userBase",
+ UserObjectClasses: []string{"new_userOhjectClasses"},
+ UserFilters: []string{"new_userFilters"},
+ Timeout: durationpb.New(time.Second),
+ Attributes: &idp_grpc.LDAPAttributes{
+ IdAttribute: "new_idAttribute",
+ FirstNameAttribute: "new_firstNameAttribute",
+ LastNameAttribute: "new_lastNameAttribute",
+ DisplayNameAttribute: "new_displayNameAttribute",
+ NickNameAttribute: "new_nickNameAttribute",
+ PreferredUsernameAttribute: "new_preferredUsernameAttribute",
+ EmailAttribute: "new_emailAttribute",
+ EmailVerifiedAttribute: "new_emailVerifiedAttribute",
+ PhoneAttribute: "new_phoneAttribute",
+ PhoneVerifiedAttribute: "new_phoneVerifiedAttribute",
+ PreferredLanguageAttribute: "new_preferredLanguageAttribute",
+ AvatarUrlAttribute: "new_avatarUrlAttribute",
+ ProfileAttribute: "new_profileAttribute",
+ },
+ ProviderOptions: &idp_grpc.Options{
+ IsLinkingAllowed: true,
+ IsCreationAllowed: true,
+ IsAutoCreation: true,
+ IsAutoUpdate: true,
+ AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for ldap
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateLdap, err := idpRepo.GetLDAP(IAMCTX, pool, idpRepo.IDCondition(addLdap.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.idp.ldap.v2.changed
+ // idp
+ assert.Equal(t, instanceID, updateLdap.InstanceID)
+ assert.Equal(t, orgID, *updateLdap.OrgID)
+ assert.Equal(t, addLdap.Id, updateLdap.ID)
+ assert.Equal(t, name, updateLdap.Name)
+ assert.Equal(t, domain.IDPTypeLDAP, domain.IDPType(*updateLdap.Type))
+ assert.Equal(t, true, updateLdap.AllowLinking)
+ assert.Equal(t, true, updateLdap.AllowCreation)
+ assert.Equal(t, true, updateLdap.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateLdap.AutoLinkingField))
+ assert.WithinRange(t, updateLdap.UpdatedAt, before, after)
+
+ // ldap
+ assert.Equal(t, []string{"new_servers"}, updateLdap.Servers)
+ assert.Equal(t, false, updateLdap.StartTLS)
+ assert.Equal(t, "new_baseDN", updateLdap.BaseDN)
+ assert.Equal(t, "new_bindND", updateLdap.BindDN)
+ assert.NotEqual(t, ldap.BindPassword, updateLdap.BindPassword)
+ assert.Equal(t, "new_userBase", updateLdap.UserBase)
+ assert.Equal(t, []string{"new_userOhjectClasses"}, updateLdap.UserObjectClasses)
+ assert.Equal(t, []string{"new_userFilters"}, updateLdap.UserFilters)
+ assert.Equal(t, time.Second, updateLdap.Timeout)
+ assert.Equal(t, "new_idAttribute", updateLdap.IDAttribute)
+ assert.Equal(t, "new_firstNameAttribute", updateLdap.FirstNameAttribute)
+ assert.Equal(t, "new_lastNameAttribute", updateLdap.LastNameAttribute)
+ assert.Equal(t, "new_displayNameAttribute", updateLdap.DisplayNameAttribute)
+ assert.Equal(t, "new_nickNameAttribute", updateLdap.NickNameAttribute)
+ assert.Equal(t, "new_preferredUsernameAttribute", updateLdap.PreferredUsernameAttribute)
+ assert.Equal(t, "new_emailAttribute", updateLdap.EmailAttribute)
+ assert.Equal(t, "new_emailVerifiedAttribute", updateLdap.EmailVerifiedAttribute)
+ assert.Equal(t, "new_phoneAttribute", updateLdap.PhoneAttribute)
+ assert.Equal(t, "new_phoneVerifiedAttribute", updateLdap.PhoneVerifiedAttribute)
+ assert.Equal(t, "new_preferredLanguageAttribute", updateLdap.PreferredLanguageAttribute)
+ assert.Equal(t, "new_avatarUrlAttribute", updateLdap.AvatarURLAttribute)
+ assert.Equal(t, "new_profileAttribute", updateLdap.ProfileAttribute)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org apple added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add apple
+ before := time.Now()
+ addApple, err := MgmtClient.AddAppleProvider(IAMCTX, &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,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ apple, err := idpRepo.GetApple(IAMCTX, pool, idpRepo.IDCondition(addApple.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.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, domain.IDPType(*apple.Type))
+ assert.Equal(t, false, apple.AllowLinking)
+ assert.Equal(t, false, apple.AllowCreation)
+ assert.Equal(t, false, apple.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*apple.AutoLinkingField))
+ assert.WithinRange(t, apple.CreatedAt, before, after)
+ assert.WithinRange(t, apple.UpdatedAt, before, after)
+
+ // 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 org apple changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add apple
+ addApple, err := MgmtClient.AddAppleProvider(IAMCTX, &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()
+
+ var apple *domain.IDPApple
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ apple, err = idpRepo.GetApple(IAMCTX, pool, idpRepo.IDCondition(addApple.Id), instanceID, &orgID)
+ require.NoError(t, err)
+ assert.Equal(t, addApple.Id, apple.ID)
+ }, retryDuration, tick)
+
+ name = "new_" + name
+ // change apple
+ before := time.Now()
+ _, err = MgmtClient.UpdateAppleProvider(IAMCTX, &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,
+ },
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for apple
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateApple, err := idpRepo.GetApple(IAMCTX, pool, 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, domain.IDPType(*updateApple.Type))
+ assert.Equal(t, true, updateApple.AllowLinking)
+ assert.Equal(t, true, updateApple.AllowCreation)
+ assert.Equal(t, true, updateApple.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateApple.AutoLinkingField))
+ assert.WithinRange(t, updateApple.UpdatedAt, before, after)
+
+ // 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 org saml added reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+ federatedLogoutEnabled := false
+
+ // add saml
+ before := time.Now()
+ addSAML, err := MgmtClient.AddSAMLProvider(IAMCTX, &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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ saml, err := idpRepo.GetSAML(IAMCTX, pool, idpRepo.IDCondition(addSAML.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.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, domain.IDPType(*saml.Type))
+ assert.Equal(t, false, saml.AllowLinking)
+ assert.Equal(t, false, saml.AllowCreation)
+ assert.Equal(t, false, saml.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldEmail, domain.IDPAutoLinkingField(*saml.AutoLinkingField))
+ assert.WithinRange(t, saml.CreatedAt, before, after)
+ assert.WithinRange(t, saml.UpdatedAt, before, after)
+
+ // 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)
+ assert.Equal(t, "http://www.w3.org/2000/09/xmldsig#rsa-sha1", saml.SignatureAlgorithm)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org saml changed reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+ federatedLogoutEnabled := false
+
+ // add saml
+ addSAML, err := MgmtClient.AddSAMLProvider(IAMCTX, &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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA1,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ var saml *domain.IDPSAML
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ saml, err = idpRepo.GetSAML(IAMCTX, pool, 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
+ before := time.Now()
+ _, err = MgmtClient.UpdateSAMLProvider(IAMCTX, &management.UpdateSAMLProviderRequest{
+ Id: addSAML.Id,
+ Name: name,
+ 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,
+ },
+ SignatureAlgorithm: idp.SAMLSignatureAlgorithm_SAML_SIGNATURE_RSA_SHA256,
+ })
+ after := time.Now()
+ require.NoError(t, err)
+
+ // check values for apple
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ updateSAML, err := idpRepo.GetSAML(IAMCTX, pool, idpRepo.IDCondition(addSAML.Id), instanceID, &orgID)
+ require.NoError(t, err)
+
+ // event org.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, domain.IDPType(*updateSAML.Type))
+ assert.Equal(t, true, updateSAML.AllowLinking)
+ assert.Equal(t, true, updateSAML.AllowCreation)
+ assert.Equal(t, true, updateSAML.AllowAutoUpdate)
+ assert.Equal(t, domain.IDPAutoLinkingFieldUserName, domain.IDPAutoLinkingField(*updateSAML.AutoLinkingField))
+ assert.WithinRange(t, updateSAML.UpdatedAt, before, after)
+
+ // saml
+ assert.Equal(t, validSAMLMetadata2, updateSAML.Metadata)
+ assert.NotNil(t, updateSAML.Key)
+ assert.NotNil(t, updateSAML.Certificate)
+ 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)
+ assert.Equal(t, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", updateSAML.SignatureAlgorithm)
+ }, retryDuration, tick)
+ })
+
+ t.Run("test org iam remove reduces", func(t *testing.T) {
+ name := gofakeit.Name()
+
+ // add idp
+ addOIDC, err := MgmtClient.AddOrgOIDCIDP(IAMCTX, &management.AddOrgOIDCIDPRequest{
+ Name: name,
+ StylingType: idp_grpc.IDPStylingType_STYLING_TYPE_GOOGLE,
+ ClientId: "clientID",
+ ClientSecret: "clientSecret",
+ Issuer: "issuer",
+ Scopes: []string{"scope"},
+ DisplayNameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ UsernameMapping: idp.OIDCMappingField_OIDC_MAPPING_FIELD_EMAIL,
+ AutoRegister: true,
+ })
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ // check idp exists
+ retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.NoError(t, err)
+ }, retryDuration, tick)
+
+ // remove idp
+ _, err = MgmtClient.DeleteProvider(IAMCTX, &management.DeleteProviderRequest{
+ Id: addOIDC.IdpId,
+ })
+ require.NoError(t, err)
+
+ // check idp is removed
+ retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute)
+ assert.EventuallyWithT(t, func(t *assert.CollectT) {
+ _, err := idpRepo.Get(IAMCTX, pool,
+ idpRepo.IDCondition(addOIDC.IdpId),
+ instanceID,
+ &orgID,
+ )
+ require.ErrorIs(t, &database.NoRowFoundError{}, err)
+ }, retryDuration, tick)
+ })
+}
diff --git a/backend/v3/storage/database/repository/id_provider.go b/backend/v3/storage/database/repository/id_provider.go
new file mode 100644
index 00000000000..9f92de35ec5
--- /dev/null
+++ b/backend/v3/storage/database/repository/id_provider.go
@@ -0,0 +1,638 @@
+package repository
+
+import (
+ "context"
+ "encoding/json"
+ "time"
+
+ "github.com/zitadel/zitadel/backend/v3/domain"
+ "github.com/zitadel/zitadel/backend/v3/storage/database"
+)
+
+var _ domain.IDProviderRepository = (*idProvider)(nil)
+
+type idProvider struct{}
+
+func IDProviderRepository() domain.IDProviderRepository {
+ return new(idProvider)
+}
+
+const queryIDProviderStmt = `SELECT instance_id, org_id, id, state, name, type, auto_register, allow_creation, allow_auto_creation,` +
+ ` allow_auto_update, allow_linking, auto_linking_field, styling_type, payload, created_at, updated_at` +
+ ` FROM zitadel.identity_providers`
+
+func (i *idProvider) Get(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IdentityProvider, error) {
+ builder := database.StatementBuilder{}
+
+ builder.WriteString(queryIDProviderStmt)
+
+ conditions := []database.Condition{id, i.InstanceIDCondition(instanceID), i.OrgIDCondition(orgID)}
+
+ writeCondition(&builder, database.And(conditions...))
+
+ return scanIDProvider(ctx, client, &builder)
+}
+
+func (i *idProvider) List(ctx context.Context, client database.QueryExecutor, conditions ...database.Condition) ([]*domain.IdentityProvider, error) {
+ builder := database.StatementBuilder{}
+
+ builder.WriteString(queryIDProviderStmt)
+
+ if conditions != nil {
+ writeCondition(&builder, database.And(conditions...))
+ }
+
+ orderBy := database.OrderBy(i.CreatedAtColumn())
+ orderBy.Write(&builder)
+
+ return scanIDProviders(ctx, client, &builder)
+}
+
+const createIDProviderStmtStart = `INSERT INTO zitadel.identity_providers` +
+ ` (instance_id, org_id, id, state, name, type, allow_creation, allow_auto_creation,` +
+ ` allow_auto_update, allow_linking, styling_type, payload) VALUES (`
+
+const createIDProviderStmtEnd = `) RETURNING created_at, updated_at`
+
+func (i *idProvider) Create(ctx context.Context, client database.QueryExecutor, idp *domain.IdentityProvider) error {
+ builder := database.StatementBuilder{}
+
+ builder.WriteString(createIDProviderStmtStart)
+
+ builder.WriteArgs(
+ idp.InstanceID,
+ idp.OrgID,
+ idp.ID,
+ idp.State,
+ idp.Name,
+ idp.Type,
+ idp.AllowCreation,
+ idp.AllowAutoCreation,
+ idp.AllowAutoUpdate,
+ idp.AllowLinking,
+ idp.StylingType,
+ string(idp.Payload))
+
+ builder.WriteString(createIDProviderStmtEnd)
+
+ err := client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&idp.CreatedAt, &idp.UpdatedAt)
+ return err
+}
+
+func (i *idProvider) Update(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string, changes ...database.Change) (int64, error) {
+ if changes == nil {
+ return 0, database.ErrNoChanges
+ }
+ changes = append(changes, i.SetUpdatedAt(nil))
+ builder := database.StatementBuilder{}
+ builder.WriteString(`UPDATE zitadel.identity_providers SET `)
+
+ conditions := []database.Condition{
+ id,
+ i.InstanceIDCondition(instanceID),
+ i.OrgIDCondition(orgID),
+ }
+ database.Changes(changes).Write(&builder)
+ writeCondition(&builder, database.And(conditions...))
+
+ stmt := builder.String()
+
+ return client.Exec(ctx, stmt, builder.Args()...)
+}
+
+func (i *idProvider) Delete(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (int64, error) {
+ builder := database.StatementBuilder{}
+
+ builder.WriteString(`DELETE FROM zitadel.identity_providers`)
+
+ conditions := []database.Condition{
+ id,
+ i.InstanceIDCondition(instanceID),
+ i.OrgIDCondition(orgID),
+ }
+ writeCondition(&builder, database.And(conditions...))
+
+ return client.Exec(ctx, builder.String(), builder.Args()...)
+}
+
+func (i *idProvider) GetOIDC(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPOIDC, error) {
+ idpOIDC := &domain.IDPOIDC{}
+ var err error
+
+ idpOIDC.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpOIDC.Type != nil {
+ idpType = *idpOIDC.Type
+ }
+
+ if idpType != domain.IDPTypeOIDC {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeOIDC, idpType)
+ }
+
+ err = json.Unmarshal(idpOIDC.Payload, idpOIDC)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpOIDC, nil
+}
+
+func (i *idProvider) GetJWT(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPJWT, error) {
+ idpJWT := &domain.IDPJWT{}
+ var err error
+
+ idpJWT.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpJWT.Type != nil {
+ idpType = *idpJWT.Type
+ }
+
+ if idpType != domain.IDPTypeJWT {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeJWT, idpType)
+ }
+
+ err = json.Unmarshal(idpJWT.Payload, idpJWT)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpJWT, nil
+}
+
+func (i *idProvider) GetOAuth(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPOAuth, error) {
+ idpOAuth := &domain.IDPOAuth{}
+ var err error
+
+ idpOAuth.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpOAuth.Type != nil {
+ idpType = *idpOAuth.Type
+ }
+
+ if idpType != domain.IDPTypeOAuth {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeOAuth, idpType)
+ }
+
+ err = json.Unmarshal(idpOAuth.Payload, idpOAuth)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpOAuth, nil
+}
+
+func (i *idProvider) GetAzureAD(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPAzureAD, error) {
+ idpAzure := &domain.IDPAzureAD{}
+ var err error
+
+ idpAzure.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpAzure.Type != nil {
+ idpType = *idpAzure.Type
+ }
+
+ if idpType != domain.IDPTypeAzure {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeAzure, idpType)
+ }
+
+ err = json.Unmarshal(idpAzure.Payload, idpAzure)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpAzure, nil
+}
+
+func (i *idProvider) GetGoogle(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPGoogle, error) {
+ idpGoogle := &domain.IDPGoogle{}
+ var err error
+
+ idpGoogle.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpGoogle.Type != nil {
+ idpType = *idpGoogle.Type
+ }
+
+ if idpType != domain.IDPTypeGoogle {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeGoogle, idpType)
+ }
+
+ err = json.Unmarshal(idpGoogle.Payload, idpGoogle)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpGoogle, nil
+}
+
+func (i *idProvider) GetGithub(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPGithub, error) {
+ idpGithub := &domain.IDPGithub{}
+ var err error
+
+ idpGithub.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpGithub.Type != nil {
+ idpType = *idpGithub.Type
+ }
+
+ if idpType != domain.IDPTypeGitHub {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeGitHub, idpType)
+ }
+
+ err = json.Unmarshal(idpGithub.Payload, idpGithub)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpGithub, nil
+}
+
+func (i *idProvider) GetGithubEnterprise(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPGithubEnterprise, error) {
+ idpGithubEnterprise := &domain.IDPGithubEnterprise{}
+ var err error
+
+ idpGithubEnterprise.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpGithubEnterprise.Type != nil {
+ idpType = *idpGithubEnterprise.Type
+ }
+
+ if idpType != domain.IDPTypeGitHubEnterprise {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeGitHubEnterprise, idpType)
+ }
+
+ err = json.Unmarshal(idpGithubEnterprise.Payload, idpGithubEnterprise)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpGithubEnterprise, nil
+}
+
+func (i *idProvider) GetGitlab(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPGitlab, error) {
+ idpGitlab := &domain.IDPGitlab{}
+ var err error
+
+ idpGitlab.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpGitlab.Type != nil {
+ idpType = *idpGitlab.Type
+ }
+
+ if idpType != domain.IDPTypeGitLab {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeGitLab, idpType)
+ }
+
+ err = json.Unmarshal(idpGitlab.Payload, idpGitlab)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpGitlab, nil
+}
+
+func (i *idProvider) GetGitlabSelfHosting(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPGitlabSelfHosting, error) {
+ idpGitlabSelfHosting := &domain.IDPGitlabSelfHosting{}
+ var err error
+
+ idpGitlabSelfHosting.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if idpGitlabSelfHosting.Type != nil {
+ idpType = *idpGitlabSelfHosting.Type
+ }
+
+ if idpType != domain.IDPTypeGitLabSelfHosted {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeGitLabSelfHosted, idpType)
+ }
+
+ err = json.Unmarshal(idpGitlabSelfHosting.Payload, idpGitlabSelfHosting)
+ if err != nil {
+ return nil, err
+ }
+
+ return idpGitlabSelfHosting, nil
+}
+
+func (i *idProvider) GetLDAP(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPLDAP, error) {
+ ldap := &domain.IDPLDAP{}
+ var err error
+
+ ldap.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if ldap.Type != nil {
+ idpType = *ldap.Type
+ }
+
+ if idpType != domain.IDPTypeLDAP {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeLDAP, idpType)
+ }
+
+ err = json.Unmarshal(ldap.Payload, ldap)
+ if err != nil {
+ return nil, err
+ }
+
+ return ldap, nil
+}
+
+func (i *idProvider) GetApple(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPApple, error) {
+ apple := &domain.IDPApple{}
+ var err error
+
+ apple.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if apple.Type != nil {
+ idpType = *apple.Type
+ }
+
+ if idpType != domain.IDPTypeApple {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeApple, idpType)
+ }
+
+ err = json.Unmarshal(apple.Payload, apple)
+ if err != nil {
+ return nil, err
+ }
+
+ return apple, nil
+}
+
+func (i *idProvider) GetSAML(ctx context.Context, client database.QueryExecutor, id domain.IDPIdentifierCondition, instanceID string, orgID *string) (*domain.IDPSAML, error) {
+ saml := &domain.IDPSAML{}
+ var err error
+
+ saml.IdentityProvider, err = i.Get(ctx, client, id, instanceID, orgID)
+ if err != nil {
+ return nil, err
+ }
+
+ var idpType domain.IDPType
+ if saml.Type != nil {
+ idpType = *saml.Type
+ }
+
+ if idpType != domain.IDPTypeSAML {
+ return nil, domain.NewIDPWrongTypeError(domain.IDPTypeSAML, idpType)
+ }
+
+ err = json.Unmarshal(saml.Payload, saml)
+ if err != nil {
+ return nil, err
+ }
+
+ return saml, nil
+}
+
+// -------------------------------------------------------------
+// columns
+// -------------------------------------------------------------
+
+func (idProvider) InstanceIDColumn() database.Column {
+ return database.NewColumn("identity_providers", "instance_id")
+}
+
+func (idProvider) OrgIDColumn() database.Column {
+ return database.NewColumn("identity_providers", "org_id")
+}
+
+func (idProvider) IDColumn() database.Column {
+ return database.NewColumn("identity_providers", "id")
+}
+
+func (idProvider) StateColumn() database.Column {
+ return database.NewColumn("identity_providers", "state")
+}
+
+func (idProvider) NameColumn() database.Column {
+ return database.NewColumn("identity_providers", "name")
+}
+
+func (idProvider) TypeColumn() database.Column {
+ return database.NewColumn("identity_providers", "type")
+}
+
+func (idProvider) AutoRegisterColumn() database.Column {
+ return database.NewColumn("identity_providers", "auto_register")
+}
+
+func (idProvider) AllowCreationColumn() database.Column {
+ return database.NewColumn("identity_providers", "allow_creation")
+}
+
+func (idProvider) AllowAutoCreationColumn() database.Column {
+ return database.NewColumn("identity_providers", "allow_auto_creation")
+}
+
+func (idProvider) AllowAutoUpdateColumn() database.Column {
+ return database.NewColumn("identity_providers", "allow_auto_update")
+}
+
+func (idProvider) AllowLinkingColumn() database.Column {
+ return database.NewColumn("identity_providers", "allow_linking")
+}
+
+func (idProvider) AllowAutoLinkingColumn() database.Column {
+ return database.NewColumn("identity_providers", "auto_linking_field")
+}
+
+func (idProvider) StylingTypeColumn() database.Column {
+ return database.NewColumn("identity_providers", "styling_type")
+}
+
+func (idProvider) PayloadColumn() database.Column {
+ return database.NewColumn("identity_providers", "payload")
+}
+
+func (idProvider) CreatedAtColumn() database.Column {
+ return database.NewColumn("identity_providers", "created_at")
+}
+
+func (idProvider) UpdatedAtColumn() database.Column {
+ return database.NewColumn("identity_providers", "updated_at")
+}
+
+// -------------------------------------------------------------
+// conditions
+// -------------------------------------------------------------
+
+func (i idProvider) InstanceIDCondition(id string) database.Condition {
+ return database.NewTextCondition(i.InstanceIDColumn(), database.TextOperationEqual, id)
+}
+
+func (i idProvider) OrgIDCondition(id *string) database.Condition {
+ if id == nil {
+ return database.IsNull(i.OrgIDColumn())
+ }
+ return database.NewTextCondition(i.OrgIDColumn(), database.TextOperationEqual, *id)
+}
+
+func (i idProvider) IDCondition(id string) domain.IDPIdentifierCondition {
+ return database.NewTextCondition(i.IDColumn(), database.TextOperationEqual, id)
+}
+
+func (i idProvider) StateCondition(state domain.IDPState) database.Condition {
+ return database.NewTextCondition(i.StateColumn(), database.TextOperationEqual, state.String())
+}
+
+func (i idProvider) NameCondition(name string) domain.IDPIdentifierCondition {
+ return database.NewTextCondition(i.NameColumn(), database.TextOperationEqual, name)
+}
+
+func (i idProvider) TypeCondition(typ domain.IDPType) database.Condition {
+ return database.NewNumberCondition(i.TypeColumn(), database.NumberOperationEqual, typ)
+}
+
+func (i idProvider) AutoRegisterCondition(allow bool) database.Condition {
+ return database.NewBooleanCondition(i.AutoRegisterColumn(), allow)
+}
+
+func (i idProvider) AllowCreationCondition(allow bool) database.Condition {
+ return database.NewBooleanCondition(i.AllowCreationColumn(), allow)
+}
+
+func (i idProvider) AllowAutoCreationCondition(allow bool) database.Condition {
+ return database.NewBooleanCondition(i.AllowAutoCreationColumn(), allow)
+}
+
+func (i idProvider) AllowAutoUpdateCondition(allow bool) database.Condition {
+ return database.NewBooleanCondition(i.AllowAutoUpdateColumn(), allow)
+}
+
+func (i idProvider) AllowLinkingCondition(allow bool) database.Condition {
+ return database.NewBooleanCondition(i.AllowLinkingColumn(), allow)
+}
+
+func (i idProvider) AllowAutoLinkingCondition(linkingType domain.IDPAutoLinkingField) database.Condition {
+ return database.NewTextCondition(i.AllowAutoLinkingColumn(), database.TextOperationEqual, linkingType.String())
+}
+
+func (i idProvider) StylingTypeCondition(style int16) database.Condition {
+ return database.NewNumberCondition(i.StylingTypeColumn(), database.NumberOperationEqual, style)
+}
+
+func (i idProvider) PayloadCondition(payload string) database.Condition {
+ return database.NewTextCondition(i.PayloadColumn(), database.TextOperationEqual, payload)
+}
+
+// -------------------------------------------------------------
+// changes
+// -------------------------------------------------------------
+
+func (i idProvider) SetName(name string) database.Change {
+ return database.NewChange(i.NameColumn(), name)
+}
+
+func (i idProvider) SetState(state domain.IDPState) database.Change {
+ return database.NewChange(i.StateColumn(), state)
+}
+
+func (i idProvider) SetAllowCreation(allow bool) database.Change {
+ return database.NewChange(i.AllowCreationColumn(), allow)
+}
+
+func (i idProvider) SetAutoRegister(allow bool) database.Change {
+ return database.NewChange(i.AutoRegisterColumn(), allow)
+}
+
+func (i idProvider) SetAllowAutoCreation(allow bool) database.Change {
+ return database.NewChange(i.AllowAutoCreationColumn(), allow)
+}
+
+func (i idProvider) SetAllowAutoUpdate(allow bool) database.Change {
+ return database.NewChange(i.AllowAutoUpdateColumn(), allow)
+}
+
+func (i idProvider) SetAllowLinking(allow bool) database.Change {
+ return database.NewChange(i.AllowLinkingColumn(), allow)
+}
+
+func (i idProvider) SetAutoAllowLinking(allow bool) database.Change {
+ return database.NewChange(i.AllowAutoLinkingColumn(), allow)
+}
+
+func (i idProvider) SetStylingType(stylingType int16) database.Change {
+ return database.NewChange(i.StylingTypeColumn(), stylingType)
+}
+
+func (i idProvider) SetPayload(payload string) database.Change {
+ return database.NewChange(i.PayloadColumn(), payload)
+}
+
+func (i idProvider) SetUpdatedAt(updatedAt *time.Time) database.Change {
+ return database.NewChangePtr(i.UpdatedAtColumn(), updatedAt)
+}
+
+func scanIDProvider(ctx context.Context, querier database.Querier, builder *database.StatementBuilder) (*domain.IdentityProvider, error) {
+ idp := &domain.IdentityProvider{}
+ rows, err := querier.Query(ctx, builder.String(), builder.Args()...)
+ if err != nil {
+ return nil, err
+ }
+
+ err = rows.(database.CollectableRows).CollectExactlyOneRow(idp)
+ if err != nil {
+ return nil, err
+ }
+
+ return idp, err
+}
+
+func scanIDProviders(ctx context.Context, querier database.Querier, builder *database.StatementBuilder) ([]*domain.IdentityProvider, error) {
+ idps := []*domain.IdentityProvider{}
+
+ rows, err := querier.Query(ctx, builder.String(), builder.Args()...)
+ if err != nil {
+ return nil, err
+ }
+
+ err = rows.(database.CollectableRows).Collect(&idps)
+ if err != nil {
+ return nil, err
+ }
+
+ return idps, nil
+}
diff --git a/backend/v3/storage/database/repository/id_provider_test.go b/backend/v3/storage/database/repository/id_provider_test.go
new file mode 100644
index 00000000000..bab64f8e461
--- /dev/null
+++ b/backend/v3/storage/database/repository/id_provider_test.go
@@ -0,0 +1,1954 @@
+package repository_test
+
+import (
+ "testing"
+ "time"
+
+ "github.com/brianvoe/gofakeit/v6"
+ "github.com/muhlemmer/gu"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/zitadel/zitadel/backend/v3/domain"
+ "github.com/zitadel/zitadel/backend/v3/storage/database"
+ "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
+)
+
+var stylingType int16 = 1
+
+func TestCreateIDProvider(t *testing.T) {
+ beforeCreate := time.Now()
+ tx, err := pool.Begin(t.Context(), nil)
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back transaction: %v", err)
+ }
+ }()
+
+ // create instance
+ instanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: instanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ orgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: orgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ type test struct {
+ name string
+ testFunc func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider
+ idp domain.IdentityProvider
+ err error
+ }
+
+ // TESTS
+ tests := []test{
+ {
+ name: "happy path",
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ },
+ {
+ name: "create idp without name",
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ // Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.CheckError),
+ },
+ {
+ name: "adding idp with same id twice",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idpRepo := repository.IDProviderRepository()
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ // change the name to make sure same only the id clashes
+ org.Name = gofakeit.Name()
+ return &idp
+ },
+ err: new(database.UniqueError),
+ },
+ {
+ name: "adding idp with same name twice",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idpRepo := repository.IDProviderRepository()
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ // change the id to make sure same name causes an error
+ idp.ID = gofakeit.Name()
+ return &idp
+ },
+ err: new(database.UniqueError),
+ },
+ func() test {
+ id := gofakeit.Name()
+ name := gofakeit.Name()
+ return test{
+ name: "adding idp with same name, id, different instance",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ // create instance
+ newInstId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: newInstId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err := instanceRepo.Create(t.Context(), tx, &instance)
+ assert.Nil(t, err)
+
+ // create org
+ newOrgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: newOrgId,
+ Name: gofakeit.Name(),
+ InstanceID: newInstId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+ idp := domain.IdentityProvider{
+ InstanceID: newInstId,
+ OrgID: &newOrgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err = idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ // change the instanceID to a different instance
+ idp.InstanceID = instanceId
+ // change the OrgId to a different organization
+ idp.OrgID = &orgId
+ return &idp
+ },
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ }
+ }(),
+ {
+ name: "adding idp with no id",
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ // ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.CheckError),
+ },
+ {
+ name: "adding idp with no name",
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ // Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.CheckError),
+ },
+ {
+ name: "adding idp with no instance id",
+ idp: domain.IdentityProvider{
+ // InstanceID: instanceId,
+ OrgID: &orgId,
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.IntegrityViolationError),
+ },
+ {
+ name: "adding idp with non existent instance id",
+ idp: domain.IdentityProvider{
+ InstanceID: gofakeit.Name(),
+ OrgID: &orgId,
+ State: domain.IDPStateActive,
+ ID: gofakeit.Name(),
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.ForeignKeyError),
+ },
+ {
+ name: "adding idp with non existent org id",
+ idp: domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: gu.Ptr(gofakeit.Name()),
+ State: domain.IDPStateActive,
+ ID: gofakeit.Name(),
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ },
+ err: new(database.ForeignKeyError),
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tx, err := tx.Begin(t.Context())
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back savepoint: %v", err)
+ }
+ }()
+
+ var idp *domain.IdentityProvider
+ if tt.testFunc != nil {
+ idp = tt.testFunc(t, tx)
+ } else {
+ idp = &tt.idp
+ }
+ idpRepo := repository.IDProviderRepository()
+
+ // create idp
+
+ err = idpRepo.Create(t.Context(), tx, idp)
+ assert.ErrorIs(t, err, tt.err)
+ if err != nil {
+ return
+ }
+ afterCreate := time.Now()
+
+ // check organization values
+ idp, err = idpRepo.Get(t.Context(), tx,
+ idpRepo.IDCondition(idp.ID),
+ idp.InstanceID,
+ idp.OrgID,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, tt.idp.InstanceID, idp.InstanceID)
+ assert.Equal(t, tt.idp.OrgID, idp.OrgID)
+ assert.Equal(t, tt.idp.State, idp.State)
+ assert.Equal(t, tt.idp.ID, idp.ID)
+ assert.Equal(t, tt.idp.Name, idp.Name)
+ assert.Equal(t, tt.idp.Type, idp.Type)
+ assert.Equal(t, tt.idp.AllowCreation, idp.AllowCreation)
+ assert.Equal(t, tt.idp.AllowAutoCreation, idp.AllowAutoCreation)
+ assert.Equal(t, tt.idp.AllowAutoUpdate, idp.AllowAutoUpdate)
+ assert.Equal(t, tt.idp.AllowLinking, idp.AllowLinking)
+ assert.Equal(t, tt.idp.StylingType, idp.StylingType)
+ assert.Equal(t, tt.idp.Payload, idp.Payload)
+ assert.WithinRange(t, idp.CreatedAt, beforeCreate, afterCreate)
+ assert.WithinRange(t, idp.UpdatedAt, beforeCreate, afterCreate)
+ })
+ }
+}
+
+func TestUpdateIDProvider(t *testing.T) {
+ beforeUpdate := time.Now()
+ tx, err := pool.Begin(t.Context(), nil)
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back transaction: %v", err)
+ }
+ }()
+
+ // create instance
+ instanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: instanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ orgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: orgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ tests := []struct {
+ name string
+ testFunc func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider
+ update []database.Change
+ rowsAffected int64
+ }{
+ {
+ name: "happy path update name",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.Name = "new_name"
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetName("new_name")},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update state",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.State = domain.IDPStateInactive
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetState(domain.IDPStateInactive)},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update AllowCreation",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.AllowCreation = false
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetAllowCreation(false)},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update AllowAutoCreation",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.AllowAutoCreation = false
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetAllowAutoCreation(false)},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update AllowLinking",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.AllowLinking = false
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetAllowLinking(false)},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update StylingType",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ newStyleType := int16(2)
+ idp.StylingType = &newStyleType
+ return &idp
+ },
+ update: []database.Change{idpRepo.SetStylingType(2)},
+ rowsAffected: 1,
+ },
+ {
+ name: "happy path update Payload",
+ testFunc: func(t *testing.T, tx database.QueryExecutor) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.Payload = []byte(`{"json": {}}`)
+ return &idp
+ },
+ // update: []database.Change{idpRepo.SetPayload("{{}}")},
+ update: []database.Change{idpRepo.SetPayload(`{"json": {}}`)},
+ rowsAffected: 1,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tx, err := tx.Begin(t.Context())
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back savepoint: %v", err)
+ }
+ }()
+ // organizationRepo := repository.OrganizationRepository()
+ idpRepo := repository.IDProviderRepository()
+
+ createdIDP := tt.testFunc(t, tx)
+
+ // update idp
+ rowsAffected, err := idpRepo.Update(t.Context(), tx,
+ idpRepo.IDCondition(createdIDP.ID),
+ createdIDP.InstanceID,
+ createdIDP.OrgID,
+ tt.update...,
+ )
+ afterUpdate := time.Now()
+ require.NoError(t, err)
+
+ assert.Equal(t, tt.rowsAffected, rowsAffected)
+
+ if rowsAffected == 0 {
+ return
+ }
+
+ // check idp values
+ idp, err := idpRepo.Get(t.Context(), tx,
+ idpRepo.IDCondition(createdIDP.ID),
+ createdIDP.InstanceID,
+ createdIDP.OrgID,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, createdIDP.InstanceID, idp.InstanceID)
+ assert.Equal(t, createdIDP.OrgID, idp.OrgID)
+ assert.Equal(t, createdIDP.State, idp.State)
+ assert.Equal(t, createdIDP.ID, idp.ID)
+ assert.Equal(t, createdIDP.Name, idp.Name)
+ assert.Equal(t, createdIDP.Type, idp.Type)
+ assert.Equal(t, createdIDP.AllowCreation, idp.AllowCreation)
+ assert.Equal(t, createdIDP.AllowAutoCreation, idp.AllowAutoCreation)
+ assert.Equal(t, createdIDP.AllowAutoUpdate, idp.AllowAutoUpdate)
+ assert.Equal(t, createdIDP.AllowLinking, idp.AllowLinking)
+ assert.Equal(t, createdIDP.StylingType, idp.StylingType)
+ assert.Equal(t, createdIDP.Payload, idp.Payload)
+ assert.WithinRange(t, idp.UpdatedAt, beforeUpdate, afterUpdate)
+ })
+ }
+}
+
+func TestGetIDProvider(t *testing.T) {
+ tx, err := pool.Begin(t.Context(), nil)
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back transaction: %v", err)
+ }
+ }()
+
+ // create instance
+ instanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: instanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ orgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: orgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ // create organization
+ // this org is created as an additional org which should NOT
+ // be returned in the results of the tests
+ preexistingOrg := domain.Organization{
+ ID: gofakeit.Name(),
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ err = organizationRepo.Create(t.Context(), tx, &preexistingOrg)
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+ type test struct {
+ name string
+ testFunc func(t *testing.T) *domain.IdentityProvider
+ idpIdentifierCondition database.Condition
+ err error
+ }
+
+ tests := []test{
+ func() test {
+ id := gofakeit.Name()
+ return test{
+ name: "happy path get using id",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.IDCondition(id),
+ }
+ }(),
+ func() test {
+ name := gofakeit.Name()
+ return test{
+ name: "happy path get using name",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.NameCondition(name),
+ }
+ }(),
+ {
+ name: "happy path using styling type",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ stylingType := 2
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: gu.Ptr(int16(stylingType)),
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.StylingTypeCondition(2),
+ },
+ {
+ name: "get using non existent id",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.IDCondition("non-existent-id"),
+ err: new(database.NoRowFoundError),
+ },
+ {
+ name: "get using non existent name",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.NameCondition("non-existent-name"),
+ err: new(database.NoRowFoundError),
+ },
+ func() test {
+ id := gofakeit.Name()
+ return test{
+ name: "non existent orgID",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.OrgID = gu.Ptr("non-existent-orgID")
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.IDCondition(id),
+ err: new(database.NoRowFoundError),
+ }
+ }(),
+ func() test {
+ name := gofakeit.Name()
+ return test{
+ name: "non existent instanceID",
+ testFunc: func(t *testing.T) *domain.IdentityProvider {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ idp.InstanceID = "non-existent-instanceID"
+ return &idp
+ },
+ idpIdentifierCondition: idpRepo.NameCondition(name),
+ err: new(database.NoRowFoundError),
+ }
+ }(),
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+
+ var idp *domain.IdentityProvider
+ if tt.testFunc != nil {
+ idp = tt.testFunc(t)
+ }
+
+ // get idp
+ returnedIDP, err := idpRepo.Get(t.Context(), tx,
+ tt.idpIdentifierCondition,
+ idp.InstanceID,
+ idp.OrgID,
+ )
+ if err != nil {
+ require.ErrorIs(t, tt.err, err)
+ return
+ }
+
+ assert.Equal(t, returnedIDP.InstanceID, idp.InstanceID)
+ assert.Equal(t, returnedIDP.OrgID, idp.OrgID)
+ assert.Equal(t, returnedIDP.State, idp.State)
+ assert.Equal(t, returnedIDP.ID, idp.ID)
+ assert.Equal(t, returnedIDP.Name, idp.Name)
+ assert.Equal(t, returnedIDP.Type, idp.Type)
+ assert.Equal(t, returnedIDP.AllowCreation, idp.AllowCreation)
+ assert.Equal(t, returnedIDP.AllowAutoCreation, idp.AllowAutoCreation)
+ assert.Equal(t, returnedIDP.AllowAutoUpdate, idp.AllowAutoUpdate)
+ assert.Equal(t, returnedIDP.AllowLinking, idp.AllowLinking)
+ assert.Equal(t, returnedIDP.StylingType, idp.StylingType)
+ assert.Equal(t, returnedIDP.Payload, idp.Payload)
+ })
+ }
+}
+
+// gocognit linting fails due to number of test cases
+// and the fact that each test case has a testFunc()
+//
+//nolint:gocognit
+func TestListIDProvider(t *testing.T) {
+ tx, err := pool.Begin(t.Context(), nil)
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back transaction: %v", err)
+ }
+ }()
+
+ // create instance
+ instanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: instanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ orgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: orgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ type test struct {
+ name string
+ testFunc func(t *testing.T) []*domain.IdentityProvider
+ conditionClauses []database.Condition
+ noIDPsReturned bool
+ }
+ tests := []test{
+ {
+ name: "multiple idps filter on instance",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create instance
+ newInstanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: newInstanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ newOrgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: newOrgId,
+ Name: gofakeit.Name(),
+ InstanceID: newInstanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: newInstanceId,
+ OrgID: &newOrgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.InstanceIDCondition(instanceId)},
+ },
+ {
+ name: "multiple idps filter on org",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create org
+ newOrgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: newOrgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &newOrgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.OrgIDCondition(&orgId)},
+ },
+ {
+ name: "happy path single idp no filter",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ noOfIDPs := 1
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ },
+ {
+ name: "happy path multiple idps no filter",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ },
+ func() test {
+ id := gofakeit.Name()
+ return test{
+ name: "idp filter on id",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 1
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.IDCondition(id)},
+ }
+ }(),
+ {
+ name: "multiple idps filter on state",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ // state inactive
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ // state active
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.StateCondition(domain.IDPStateActive)},
+ },
+ func() test {
+ name := gofakeit.Name()
+ return test{
+ name: "multiple idps filter on name",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 1
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.NameCondition(name)},
+ }
+ }(),
+ {
+ name: "multiple idps filter on type",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ // type LDAP
+ Type: gu.Ptr(domain.IDPTypeLDAP),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.TypeCondition(domain.IDPTypeLDAP)},
+ },
+ {
+ name: "multiple idps filter on AllowCreation",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeLDAP),
+ // AllowCreation set to false
+ AllowCreation: false,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.AllowCreationCondition(false)},
+ },
+ {
+ name: "multiple idps filter on AllowAutoCreation",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeLDAP),
+ AllowCreation: true,
+ // AllowAutoCreation set to false
+ AllowAutoCreation: false,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.AllowAutoCreationCondition(false)},
+ },
+ {
+ name: "multiple idps filter on AllowAutoUpdate",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ // state inactive
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeLDAP),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ // AllowAutoUpdate set to false
+ AllowAutoUpdate: false,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.AllowAutoUpdateCondition(false)},
+ },
+ {
+ name: "multiple idps filter on AllowLinking",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ // state inactive
+ State: domain.IDPStateInactive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 5
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeLDAP),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ // AllowLinking set to false
+ AllowLinking: false,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.AllowLinkingCondition(false)},
+ },
+ {
+ name: "multiple idps filter on StylingType",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ var sytlingType int16 = 4
+ noOfIDPs := 1
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ // StylingType set to 4
+ StylingType: &sytlingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.StylingTypeCondition(4)},
+ },
+ func() test {
+ payload := []byte(`{"json": {}}`)
+ return test{
+ name: "multiple idps filter on Payload",
+ testFunc: func(t *testing.T) []*domain.IdentityProvider {
+ // create idp
+ // this idp is created as an additional idp which should NOT
+ // be returned in the results of this test case
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ noOfIDPs := 1
+ idps := make([]*domain.IdentityProvider, noOfIDPs)
+ for i := range noOfIDPs {
+
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: payload,
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ idps[i] = &idp
+ }
+
+ return idps
+ },
+ conditionClauses: []database.Condition{idpRepo.PayloadCondition(string(payload))},
+ }
+ }(),
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ defer func() {
+ _, err := tx.Exec(t.Context(), "DELETE FROM zitadel.identity_providers")
+ require.NoError(t, err)
+ }()
+
+ idps := tt.testFunc(t)
+
+ // check idp values
+ returnedIDPs, err := idpRepo.List(t.Context(), tx,
+ tt.conditionClauses...,
+ )
+ require.NoError(t, err)
+ if tt.noIDPsReturned {
+ assert.Nil(t, returnedIDPs)
+ return
+ }
+
+ assert.Equal(t, len(idps), len(returnedIDPs))
+ for i, idp := range idps {
+
+ assert.Equal(t, returnedIDPs[i].InstanceID, idp.InstanceID)
+ assert.Equal(t, returnedIDPs[i].OrgID, idp.OrgID)
+ assert.Equal(t, returnedIDPs[i].State, idp.State)
+ assert.Equal(t, returnedIDPs[i].ID, idp.ID)
+ assert.Equal(t, returnedIDPs[i].Name, idp.Name)
+ assert.Equal(t, returnedIDPs[i].Type, idp.Type)
+ assert.Equal(t, returnedIDPs[i].AllowCreation, idp.AllowCreation)
+ assert.Equal(t, returnedIDPs[i].AllowAutoCreation, idp.AllowAutoCreation)
+ assert.Equal(t, returnedIDPs[i].AllowAutoUpdate, idp.AllowAutoUpdate)
+ assert.Equal(t, returnedIDPs[i].AllowLinking, idp.AllowLinking)
+ assert.Equal(t, returnedIDPs[i].StylingType, idp.StylingType)
+ assert.Equal(t, returnedIDPs[i].Payload, idp.Payload)
+ }
+ })
+ }
+}
+
+func TestDeleteIDProvider(t *testing.T) {
+ tx, err := pool.Begin(t.Context(), nil)
+ require.NoError(t, err)
+ defer func() {
+ err := tx.Rollback(t.Context())
+ if err != nil {
+ t.Errorf("error rolling back transaction: %v", err)
+ }
+ }()
+
+ // create instance
+ instanceId := gofakeit.Name()
+ instance := domain.Instance{
+ ID: instanceId,
+ Name: gofakeit.Name(),
+ DefaultOrgID: "defaultOrgId",
+ IAMProjectID: "iamProject",
+ ConsoleClientID: "consoleCLient",
+ ConsoleAppID: "consoleApp",
+ DefaultLanguage: "defaultLanguage",
+ }
+ instanceRepo := repository.InstanceRepository()
+ err = instanceRepo.Create(t.Context(), tx, &instance)
+ require.NoError(t, err)
+
+ // create org
+ orgId := gofakeit.Name()
+ org := domain.Organization{
+ ID: orgId,
+ Name: gofakeit.Name(),
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
+ }
+ organizationRepo := repository.OrganizationRepository()
+ err = organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
+ idpRepo := repository.IDProviderRepository()
+
+ type test struct {
+ name string
+ testFunc func(t *testing.T)
+ idpIdentifierCondition domain.IDPIdentifierCondition
+ noOfDeletedRows int64
+ }
+ tests := []test{
+ func() test {
+ id := gofakeit.Name()
+ var noOfIDPs int64 = 1
+ return test{
+ name: "happy path delete idp filter id",
+ testFunc: func(t *testing.T) {
+ for range noOfIDPs {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: id,
+ State: domain.IDPStateActive,
+ Name: gofakeit.Name(),
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ }
+ },
+ idpIdentifierCondition: idpRepo.IDCondition(id),
+ noOfDeletedRows: noOfIDPs,
+ }
+ }(),
+ func() test {
+ name := gofakeit.Name()
+ var noOfIDPs int64 = 1
+ return test{
+ name: "happy path delete idp filter name",
+ testFunc: func(t *testing.T) {
+ for range noOfIDPs {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+
+ }
+ },
+ idpIdentifierCondition: idpRepo.NameCondition(name),
+ noOfDeletedRows: noOfIDPs,
+ }
+ }(),
+ {
+ name: "delete non existent idp",
+ idpIdentifierCondition: idpRepo.NameCondition(gofakeit.Name()),
+ },
+ func() test {
+ name := gofakeit.Name()
+ return test{
+ name: "deleted already deleted idp",
+ testFunc: func(t *testing.T) {
+ noOfIDPs := 1
+ for range noOfIDPs {
+ idp := domain.IdentityProvider{
+ InstanceID: instanceId,
+ OrgID: &orgId,
+ ID: gofakeit.Name(),
+ State: domain.IDPStateActive,
+ Name: name,
+ Type: gu.Ptr(domain.IDPTypeOIDC),
+ AllowCreation: true,
+ AllowAutoCreation: true,
+ AllowAutoUpdate: true,
+ AllowLinking: true,
+ StylingType: &stylingType,
+ Payload: []byte("{}"),
+ }
+
+ err := idpRepo.Create(t.Context(), tx, &idp)
+ require.NoError(t, err)
+ }
+
+ // delete organization
+ affectedRows, err := idpRepo.Delete(t.Context(), tx,
+ idpRepo.NameCondition(name),
+ instanceId,
+ &orgId,
+ )
+ assert.Equal(t, int64(1), affectedRows)
+ require.NoError(t, err)
+ },
+ idpIdentifierCondition: idpRepo.NameCondition(name),
+ // this test should return 0 affected rows as the idp was already deleted
+ noOfDeletedRows: 0,
+ }
+ }(),
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if tt.testFunc != nil {
+ tt.testFunc(t)
+ }
+
+ // delete idp
+ noOfDeletedRows, err := idpRepo.Delete(t.Context(), tx,
+ tt.idpIdentifierCondition,
+ instanceId,
+ &orgId,
+ )
+ require.NoError(t, err)
+ assert.Equal(t, noOfDeletedRows, tt.noOfDeletedRows)
+
+ // check idp was deleted
+ organization, err := idpRepo.Get(t.Context(), tx,
+ tt.idpIdentifierCondition,
+ instanceId,
+ &orgId,
+ )
+ require.ErrorIs(t, err, new(database.NoRowFoundError))
+ assert.Nil(t, organization)
+ })
+ }
+}
diff --git a/backend/v3/storage/database/repository/org_test.go b/backend/v3/storage/database/repository/org_test.go
index c624ffe6c1c..7e785834b5e 100644
--- a/backend/v3/storage/database/repository/org_test.go
+++ b/backend/v3/storage/database/repository/org_test.go
@@ -609,11 +609,6 @@ func TestGetOrganization(t *testing.T) {
}
require.NoError(t, err)
- if org.Name == "non existent org" {
- assert.Nil(t, returnedOrg)
- return
- }
-
assert.Equal(t, returnedOrg.ID, org.ID)
assert.Equal(t, returnedOrg.Name, org.Name)
assert.Equal(t, returnedOrg.InstanceID, org.InstanceID)
@@ -931,9 +926,7 @@ func TestDeleteOrganization(t *testing.T) {
return test{
name: "happy path delete organization filter id",
testFunc: func(t *testing.T) {
- organizations := make([]*domain.Organization, noOfOrganizations)
- for i := range noOfOrganizations {
-
+ for range noOfOrganizations {
org := domain.Organization{
ID: organizationId,
Name: gofakeit.Name(),
@@ -945,7 +938,6 @@ func TestDeleteOrganization(t *testing.T) {
err := organizationRepo.Create(t.Context(), tx, &org)
require.NoError(t, err)
- organizations[i] = &org
}
},
orgIdentifierCondition: organizationRepo.IDCondition(organizationId),
@@ -958,9 +950,7 @@ func TestDeleteOrganization(t *testing.T) {
return test{
name: "happy path delete organization filter name",
testFunc: func(t *testing.T) {
- organizations := make([]*domain.Organization, noOfOrganizations)
- for i := range noOfOrganizations {
-
+ for range noOfOrganizations {
org := domain.Organization{
ID: gofakeit.Name(),
Name: organizationName,
@@ -972,7 +962,6 @@ func TestDeleteOrganization(t *testing.T) {
err := organizationRepo.Create(t.Context(), tx, &org)
require.NoError(t, err)
- organizations[i] = &org
}
},
orgIdentifierCondition: organizationRepo.NameCondition(database.TextOperationEqual, organizationName),
@@ -991,28 +980,21 @@ func TestDeleteOrganization(t *testing.T) {
return test{
name: "deleted already deleted organization",
testFunc: func(t *testing.T) {
- noOfOrganizations := 1
- organizations := make([]*domain.Organization, noOfOrganizations)
- for i := range noOfOrganizations {
-
- org := domain.Organization{
- ID: gofakeit.Name(),
- Name: organizationName,
- InstanceID: instanceId,
- State: domain.OrgStateActive,
- }
-
- // create organization
- err := organizationRepo.Create(t.Context(), tx, &org)
- require.NoError(t, err)
-
- organizations[i] = &org
+ org := domain.Organization{
+ ID: gofakeit.Name(),
+ Name: organizationName,
+ InstanceID: instanceId,
+ State: domain.OrgStateActive,
}
+ // create organization
+ err := organizationRepo.Create(t.Context(), tx, &org)
+ require.NoError(t, err)
+
// delete organization
affectedRows, err := organizationRepo.Delete(t.Context(), tx,
database.And(
- organizationRepo.InstanceIDCondition(organizations[0].InstanceID),
+ organizationRepo.InstanceIDCondition(org.InstanceID),
organizationRepo.NameCondition(database.TextOperationEqual, organizationName),
),
)
diff --git a/internal/api/grpc/admin/instance.go b/internal/api/grpc/admin/instance.go
index a7b0316ec43..38fc9ec4d8a 100644
--- a/internal/api/grpc/admin/instance.go
+++ b/internal/api/grpc/admin/instance.go
@@ -29,7 +29,7 @@ func (s *Server) ListInstanceDomains(ctx context.Context, req *admin_pb.ListInst
return nil, err
}
return &admin_pb.ListInstanceDomainsResponse{
- Result: instance_grpc.DomainsToPb(domains.Domains),
+ Result: instance_grpc.DomainsToPb(domains.Domains),
SortingColumn: req.SortingColumn,
Details: object.ToListDetails(
domains.Count,
@@ -49,7 +49,7 @@ func (s *Server) ListInstanceTrustedDomains(ctx context.Context, req *admin_pb.L
return nil, err
}
return &admin_pb.ListInstanceTrustedDomainsResponse{
- Result: instance_grpc.TrustedDomainsToPb(domains.Domains),
+ Result: instance_grpc.TrustedDomainsToPb(domains.Domains),
SortingColumn: req.SortingColumn,
Details: object.ToListDetails(
domains.Count,
diff --git a/internal/query/projection/idp_template_relational.go b/internal/query/projection/idp_template_relational.go
new file mode 100644
index 00000000000..79d058fce6f
--- /dev/null
+++ b/internal/query/projection/idp_template_relational.go
@@ -0,0 +1,2523 @@
+package projection
+
+import (
+ "context"
+ "database/sql"
+ "encoding/json"
+
+ "github.com/zitadel/zitadel/backend/v3/domain"
+ v3_sql "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/sql"
+ "github.com/zitadel/zitadel/backend/v3/storage/database/repository"
+ internal_domain "github.com/zitadel/zitadel/internal/domain"
+ "github.com/zitadel/zitadel/internal/eventstore"
+ "github.com/zitadel/zitadel/internal/eventstore/handler/v2"
+ "github.com/zitadel/zitadel/internal/repository/idp"
+ "github.com/zitadel/zitadel/internal/repository/idpconfig"
+ "github.com/zitadel/zitadel/internal/repository/instance"
+ "github.com/zitadel/zitadel/internal/repository/org"
+ "github.com/zitadel/zitadel/internal/zerrors"
+)
+
+const (
+ IDPRelationalTable = "zitadel.identity_providers"
+ IDPRelationalOrgIdCol = "org_id"
+ IDPRelationalAutoRegisterCol = "auto_register"
+ IDPRelationalPayloadCol = "payload"
+ IDPRelationalOrgId = "org_id"
+ IDPRelationalAllowCreationCol = "allow_creation"
+ IDPRelationalAllowLinkingCol = "allow_linking"
+ IDPRelationalAllowAutoCreationCol = "allow_auto_creation"
+ IDPRelationalAllowAutoUpdateCol = "allow_auto_update"
+ IDPRelationalAllowAutoLinkingCol = "auto_linking_field"
+)
+
+type idpTemplateRelationalProjection struct {
+ idpRepo domain.IDProviderRepository
+}
+
+func newIDPTemplateRelationalProjection(ctx context.Context, config handler.Config) *handler.Handler {
+ idpRepo := repository.IDProviderRepository()
+ return handler.NewHandler(ctx, &config, &idpTemplateRelationalProjection{
+ idpRepo: idpRepo,
+ })
+}
+
+func (*idpTemplateRelationalProjection) Name() string {
+ return IDPRelationalTable
+}
+
+func (p *idpTemplateRelationalProjection) Reducers() []handler.AggregateReducer {
+ return []handler.AggregateReducer{
+ {
+ Aggregate: instance.AggregateType,
+ EventReducers: []handler.EventReducer{
+ {
+ Event: instance.IDPConfigAddedEventType,
+ Reduce: p.reduceIDPRelationalAdded,
+ },
+ {
+ Event: instance.IDPConfigChangedEventType,
+ Reduce: p.reduceIDPRelationalChanged,
+ },
+ {
+ Event: instance.IDPConfigDeactivatedEventType,
+ Reduce: p.reduceIDRelationalPDeactivated,
+ },
+ {
+ Event: instance.IDPConfigReactivatedEventType,
+ Reduce: p.reduceIDPRelationalReactivated,
+ },
+ {
+ Event: instance.IDPConfigRemovedEventType,
+ Reduce: p.reduceIDPRelationalRemoved,
+ },
+ {
+ Event: instance.IDPOIDCConfigAddedEventType,
+ Reduce: p.reduceOIDCRelationalConfigAdded,
+ },
+ {
+ Event: instance.IDPOIDCConfigChangedEventType,
+ Reduce: p.reduceOIDCRelationalConfigChanged,
+ },
+ {
+ Event: instance.IDPJWTConfigAddedEventType,
+ Reduce: p.reduceJWTRelationalConfigAdded,
+ },
+ {
+ Event: instance.IDPJWTConfigChangedEventType,
+ Reduce: p.reduceJWTRelationalConfigChanged,
+ },
+ {
+ Event: instance.OAuthIDPAddedEventType,
+ Reduce: p.reduceOAuthIDPRelationalAdded,
+ },
+ {
+ Event: instance.OAuthIDPChangedEventType,
+ Reduce: p.reduceOAuthIDPRelationalChanged,
+ },
+ {
+ Event: instance.OIDCIDPAddedEventType,
+ Reduce: p.reduceOIDCIDPRelationalAdded,
+ },
+ {
+ Event: instance.OIDCIDPChangedEventType,
+ Reduce: p.reduceOIDCIDPRelationalChanged,
+ },
+ {
+ Event: instance.OIDCIDPMigratedAzureADEventType,
+ Reduce: p.reduceOIDCIDPRelationalMigratedAzureAD,
+ },
+ {
+ Event: instance.OIDCIDPMigratedGoogleEventType,
+ Reduce: p.reduceOIDCIDPRelationalMigratedGoogle,
+ },
+ {
+ Event: instance.JWTIDPAddedEventType,
+ Reduce: p.reduceJWTIDPRelationalAdded,
+ },
+ {
+ Event: instance.JWTIDPChangedEventType,
+ Reduce: p.reduceJWTIDPRelationalChanged,
+ },
+ {
+ Event: instance.AzureADIDPAddedEventType,
+ Reduce: p.reduceAzureADIDPRelationalAdded,
+ },
+ {
+ Event: instance.AzureADIDPChangedEventType,
+ Reduce: p.reduceAzureADIDPRelationalChanged,
+ },
+ {
+ Event: instance.GitHubIDPAddedEventType,
+ Reduce: p.reduceGitHubIDPRelationalAdded,
+ },
+ {
+ Event: instance.GitHubIDPChangedEventType,
+ Reduce: p.reduceGitHubIDPRelationalChanged,
+ },
+ {
+ Event: instance.GitHubEnterpriseIDPAddedEventType,
+ Reduce: p.reduceGitHubEnterpriseIDPRelationalAdded,
+ },
+ {
+ Event: instance.GitHubEnterpriseIDPChangedEventType,
+ Reduce: p.reduceGitHubEnterpriseIDPRelationalChanged,
+ },
+ {
+ Event: instance.GitLabIDPAddedEventType,
+ Reduce: p.reduceGitLabIDPRelationalAdded,
+ },
+ {
+ Event: instance.GitLabIDPChangedEventType,
+ Reduce: p.reduceGitLabIDPRelationalChanged,
+ },
+ {
+ Event: instance.GitLabSelfHostedIDPAddedEventType,
+ Reduce: p.reduceGitLabSelfHostedIDPRelationalAdded,
+ },
+ {
+ Event: instance.GitLabSelfHostedIDPChangedEventType,
+ Reduce: p.reduceGitLabSelfHostedIDPRelationalChanged,
+ },
+ {
+ Event: instance.GoogleIDPAddedEventType,
+ Reduce: p.reduceGoogleIDPRelationalAdded,
+ },
+ {
+ Event: instance.GoogleIDPChangedEventType,
+ Reduce: p.reduceGoogleIDPRelationalChanged,
+ },
+ {
+ Event: instance.LDAPIDPAddedEventType,
+ Reduce: p.reduceLDAPIDPAdded,
+ },
+ {
+ Event: instance.LDAPIDPChangedEventType,
+ Reduce: p.reduceLDAPIDPChanged,
+ },
+ {
+ Event: instance.AppleIDPAddedEventType,
+ Reduce: p.reduceAppleIDPAdded,
+ },
+ {
+ Event: instance.AppleIDPChangedEventType,
+ Reduce: p.reduceAppleIDPChanged,
+ },
+ {
+ Event: instance.SAMLIDPAddedEventType,
+ Reduce: p.reduceSAMLIDPAdded,
+ },
+ {
+ Event: instance.SAMLIDPChangedEventType,
+ Reduce: p.reduceSAMLIDPChanged,
+ },
+ {
+ Event: instance.IDPRemovedEventType,
+ Reduce: p.reduceIDPRemoved,
+ },
+ },
+ },
+ {
+ Aggregate: org.AggregateType,
+ EventReducers: []handler.EventReducer{
+ {
+ Event: org.IDPConfigAddedEventType,
+ Reduce: p.reduceIDPRelationalAdded,
+ },
+ {
+ Event: org.IDPConfigChangedEventType,
+ Reduce: p.reduceIDPRelationalChanged,
+ },
+ {
+ Event: org.IDPConfigDeactivatedEventType,
+ Reduce: p.reduceIDRelationalPDeactivated,
+ },
+ {
+ Event: org.IDPConfigReactivatedEventType,
+ Reduce: p.reduceIDPRelationalReactivated,
+ },
+ {
+ Event: org.IDPConfigRemovedEventType,
+ Reduce: p.reduceIDPRelationalRemoved,
+ },
+ {
+ Event: org.IDPOIDCConfigAddedEventType,
+ Reduce: p.reduceOIDCRelationalConfigAdded,
+ },
+ {
+ Event: org.IDPOIDCConfigChangedEventType,
+ Reduce: p.reduceOIDCRelationalConfigChanged,
+ },
+ {
+ Event: org.IDPJWTConfigAddedEventType,
+ Reduce: p.reduceJWTRelationalConfigAdded,
+ },
+ {
+ Event: org.IDPJWTConfigChangedEventType,
+ Reduce: p.reduceJWTRelationalConfigChanged,
+ },
+ {
+ Event: org.OAuthIDPAddedEventType,
+ Reduce: p.reduceOAuthIDPRelationalAdded,
+ },
+ {
+ Event: org.OAuthIDPChangedEventType,
+ Reduce: p.reduceOAuthIDPRelationalChanged,
+ },
+ {
+ Event: org.OIDCIDPAddedEventType,
+ Reduce: p.reduceOIDCIDPRelationalAdded,
+ },
+ {
+ Event: org.OIDCIDPChangedEventType,
+ Reduce: p.reduceOIDCIDPRelationalChanged,
+ },
+ {
+ Event: org.OIDCIDPMigratedAzureADEventType,
+ Reduce: p.reduceOIDCIDPRelationalMigratedAzureAD,
+ },
+ {
+ Event: org.OIDCIDPMigratedGoogleEventType,
+ Reduce: p.reduceOIDCIDPRelationalMigratedGoogle,
+ },
+ {
+ Event: org.JWTIDPAddedEventType,
+ Reduce: p.reduceJWTIDPRelationalAdded,
+ },
+ {
+ Event: org.JWTIDPChangedEventType,
+ Reduce: p.reduceJWTIDPRelationalChanged,
+ },
+ {
+ Event: org.AzureADIDPAddedEventType,
+ Reduce: p.reduceAzureADIDPRelationalAdded,
+ },
+ {
+ Event: org.AzureADIDPChangedEventType,
+ Reduce: p.reduceAzureADIDPRelationalChanged,
+ },
+ {
+ Event: org.GitHubIDPAddedEventType,
+ Reduce: p.reduceGitHubIDPRelationalAdded,
+ },
+ {
+ Event: org.GitHubIDPChangedEventType,
+ Reduce: p.reduceGitHubIDPRelationalChanged,
+ },
+ {
+ Event: org.GitHubEnterpriseIDPAddedEventType,
+ Reduce: p.reduceGitHubEnterpriseIDPRelationalAdded,
+ },
+ {
+ Event: org.GitHubEnterpriseIDPChangedEventType,
+ Reduce: p.reduceGitHubEnterpriseIDPRelationalChanged,
+ },
+ {
+ Event: org.GitLabIDPAddedEventType,
+ Reduce: p.reduceGitLabIDPRelationalAdded,
+ },
+ {
+ Event: org.GitLabIDPChangedEventType,
+ Reduce: p.reduceGitLabIDPRelationalChanged,
+ },
+ {
+ Event: org.GitLabSelfHostedIDPAddedEventType,
+ Reduce: p.reduceGitLabSelfHostedIDPRelationalAdded,
+ },
+ {
+ Event: org.GitLabSelfHostedIDPChangedEventType,
+ Reduce: p.reduceGitLabSelfHostedIDPRelationalChanged,
+ },
+ {
+ Event: org.GoogleIDPAddedEventType,
+ Reduce: p.reduceGoogleIDPRelationalAdded,
+ },
+ {
+ Event: org.GoogleIDPChangedEventType,
+ Reduce: p.reduceGoogleIDPRelationalChanged,
+ },
+ {
+ Event: org.LDAPIDPAddedEventType,
+ Reduce: p.reduceLDAPIDPAdded,
+ },
+ {
+ Event: org.LDAPIDPChangedEventType,
+ Reduce: p.reduceLDAPIDPChanged,
+ },
+ {
+ Event: org.AppleIDPAddedEventType,
+ Reduce: p.reduceAppleIDPAdded,
+ },
+ {
+ Event: org.AppleIDPChangedEventType,
+ Reduce: p.reduceAppleIDPChanged,
+ },
+ {
+ Event: org.SAMLIDPAddedEventType,
+ Reduce: p.reduceSAMLIDPAdded,
+ },
+ {
+ Event: org.SAMLIDPChangedEventType,
+ Reduce: p.reduceSAMLIDPChanged,
+ },
+ {
+ Event: org.IDPRemovedEventType,
+ Reduce: p.reduceIDPRemoved,
+ },
+ },
+ },
+ }
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idpconfig.IDPConfigAddedEvent
+ switch e := event.(type) {
+ case *org.IDPConfigAddedEvent:
+ idpEvent = e.IDPConfigAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.IDPConfigAddedEvent:
+ idpEvent = e.IDPConfigAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YcUdQ", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigAddedEventType, instance.IDPConfigAddedEventType})
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ handler.NewCol(IDPRelationalOrgIdCol, orgId),
+ handler.NewCol(IDPIDCol, idpEvent.ConfigID),
+ handler.NewCol(IDPStateCol, domain.IDPStateActive.String()),
+ handler.NewCol(IDPNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, nil),
+ handler.NewCol(IDPRelationalAutoRegisterCol, idpEvent.AutoRegister),
+ handler.NewCol(IDPRelationalAllowCreationCol, true),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, false),
+ handler.NewCol(IDPRelationalAllowLinkingCol, true),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, nil),
+ handler.NewCol(IDPStylingTypeCol, idpEvent.StylingType),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.IDPConfigChangedEvent
+ switch e := event.(type) {
+ case *org.IDPConfigChangedEvent:
+ idpEvent = e.IDPConfigChangedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPConfigChangedEvent:
+ idpEvent = e.IDPConfigChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YVvJD", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigChangedEventType, instance.IDPConfigChangedEventType})
+ }
+
+ columns := make([]handler.Column, 0, 4)
+ if idpEvent.Name != nil {
+ columns = append(columns, handler.NewCol(IDPNameCol, *idpEvent.Name))
+ }
+ if idpEvent.StylingType != nil {
+ columns = append(columns, handler.NewCol(IDPStylingTypeCol, *idpEvent.StylingType))
+ }
+ if idpEvent.AutoRegister != nil {
+ columns = append(columns, handler.NewCol(IDPRelationalAutoRegisterCol, *idpEvent.AutoRegister))
+ }
+ if len(columns) == 0 {
+ return handler.NewNoOpStatement(&idpEvent), nil
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.ConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDRelationalPDeactivated(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.IDPConfigDeactivatedEvent
+ switch e := event.(type) {
+ case *org.IDPConfigDeactivatedEvent:
+ idpEvent = e.IDPConfigDeactivatedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPConfigDeactivatedEvent:
+ idpEvent = e.IDPConfigDeactivatedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y4O5l", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigDeactivatedEventType, instance.IDPConfigDeactivatedEventType})
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPStateCol, domain.IDPStateInactive),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.ConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDPRelationalReactivated(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.IDPConfigReactivatedEvent
+ switch e := event.(type) {
+ case *org.IDPConfigReactivatedEvent:
+ idpEvent = e.IDPConfigReactivatedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPConfigReactivatedEvent:
+ idpEvent = e.IDPConfigReactivatedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y8QyS", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigReactivatedEventType, instance.IDPConfigReactivatedEventType})
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPStateCol, domain.IDPStateActive.String()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.ConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDPRelationalRemoved(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.IDPConfigRemovedEvent
+ switch e := event.(type) {
+ case *org.IDPConfigRemovedEvent:
+ idpEvent = e.IDPConfigRemovedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPConfigRemovedEvent:
+ idpEvent = e.IDPConfigRemovedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y4zy8", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPConfigRemovedEventType, instance.IDPConfigRemovedEventType})
+ }
+
+ return handler.NewDeleteStatement(
+ &idpEvent,
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.ConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCRelationalConfigAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.OIDCConfigAddedEvent
+ switch e := event.(type) {
+ case *org.IDPOIDCConfigAddedEvent:
+ idpEvent = e.OIDCConfigAddedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPOIDCConfigAddedEvent:
+ idpEvent = e.OIDCConfigAddedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YFuAA", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPOIDCConfigAddedEventType, instance.IDPOIDCConfigAddedEventType})
+ }
+
+ payloadJSON, err := json.Marshal(idpEvent)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC),
+ handler.NewCol(UpdatedAt, idpEvent.CreatedAt()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.IDPConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCRelationalConfigChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idpconfig.OIDCConfigChangedEvent
+ switch e := event.(type) {
+ case *org.IDPOIDCConfigChangedEvent:
+ idpEvent = e.OIDCConfigChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.IDPOIDCConfigChangedEvent:
+ idpEvent = e.OIDCConfigChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y2IVI", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPOIDCConfigChangedEventType, instance.IDPOIDCConfigChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-sh6Lp", "unable to cast to tx executer")
+ }
+
+ oidc, err := p.idpRepo.GetOIDC(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.IDPConfigID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ if idpEvent.ClientID != nil {
+ oidc.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ oidc.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Issuer != nil {
+ oidc.Issuer = *idpEvent.Issuer
+ }
+ if idpEvent.AuthorizationEndpoint != nil {
+ oidc.AuthorizationEndpoint = *idpEvent.AuthorizationEndpoint
+ }
+ if idpEvent.TokenEndpoint != nil {
+ oidc.TokenEndpoint = *idpEvent.TokenEndpoint
+ }
+ if idpEvent.Scopes != nil {
+ oidc.Scopes = idpEvent.Scopes
+ }
+ if idpEvent.IDPDisplayNameMapping != nil {
+ oidc.IDPDisplayNameMapping = domain.OIDCMappingField(*idpEvent.IDPDisplayNameMapping)
+ }
+ if idpEvent.UserNameMapping != nil {
+ oidc.UserNameMapping = domain.OIDCMappingField(*idpEvent.UserNameMapping)
+ }
+
+ payloadJSON, err := json.Marshal(idpEvent)
+ if err != nil {
+ return err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(IDPTypeCol, domain.IDPTypeOIDC),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.IDPConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceJWTRelationalConfigAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idpconfig.JWTConfigAddedEvent
+ switch e := event.(type) {
+ case *org.IDPJWTConfigAddedEvent:
+ idpEvent = e.JWTConfigAddedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPJWTConfigAddedEvent:
+ idpEvent = e.JWTConfigAddedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YvPdb", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigAddedEventType, instance.IDPJWTConfigAddedEventType})
+ }
+
+ payloadJSON, err := json.Marshal(idpEvent)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(IDPTypeCol, domain.IDPTypeJWT),
+ handler.NewCol(UpdatedAt, idpEvent.CreatedAt()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.IDPConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceJWTRelationalConfigChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idpconfig.JWTConfigChangedEvent
+ switch e := event.(type) {
+ case *org.IDPJWTConfigChangedEvent:
+ idpEvent = e.JWTConfigChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.IDPJWTConfigChangedEvent:
+ idpEvent = e.JWTConfigChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y2IVI", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPJWTConfigChangedEventType, instance.IDPJWTConfigChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-sh6Lp", "unable to cast to tx executer")
+ }
+
+ jwt, err := p.idpRepo.GetJWT(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.IDPConfigID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ if idpEvent.JWTEndpoint != nil {
+ jwt.JWTEndpoint = *idpEvent.JWTEndpoint
+ }
+ if idpEvent.Issuer != nil {
+ jwt.Issuer = *idpEvent.Issuer
+ }
+ if idpEvent.KeysEndpoint != nil {
+ jwt.KeysEndpoint = *idpEvent.KeysEndpoint
+ }
+ if idpEvent.HeaderName != nil {
+ jwt.HeaderName = *idpEvent.HeaderName
+ }
+
+ payloadJSON, err := json.Marshal(idpEvent)
+ if err != nil {
+ return err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(IDPTypeCol, domain.IDPTypeJWT),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPIDCol, idpEvent.IDPConfigID),
+ handler.NewCond(IDPInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOAuthIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.OAuthIDPAddedEvent
+ switch e := event.(type) {
+ case *org.OAuthIDPAddedEvent:
+ idpEvent = e.OAuthIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.OAuthIDPAddedEvent:
+ idpEvent = e.OAuthIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Yap9ihb", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPAddedEventType, instance.OAuthIDPAddedEventType})
+ }
+
+ oauth := domain.OAuth{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ AuthorizationEndpoint: idpEvent.AuthorizationEndpoint,
+ TokenEndpoint: idpEvent.TokenEndpoint,
+ UserEndpoint: idpEvent.UserEndpoint,
+ Scopes: idpEvent.Scopes,
+ IDAttribute: idpEvent.IDAttribute,
+ UsePKCE: idpEvent.UsePKCE,
+ }
+
+ payloadJSON, err := json.Marshal(oauth)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCol(IDPRelationalOrgId, orgId),
+ handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive.String()),
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOAuth),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOAuthIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.OAuthIDPChangedEvent
+ switch e := event.(type) {
+ case *org.OAuthIDPChangedEvent:
+ idpEvent = e.OAuthIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.OAuthIDPChangedEvent:
+ idpEvent = e.OAuthIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-K1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OAuthIDPChangedEventType, instance.OAuthIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ oauth, err := p.idpRepo.GetOAuth(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &oauth.OAuth
+ payloadChanged := reduceOAuthIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.OIDCIDPAddedEvent
+ switch e := event.(type) {
+ case *org.OIDCIDPAddedEvent:
+ idpEvent = e.OIDCIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.OIDCIDPAddedEvent:
+ idpEvent = e.OIDCIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Ys02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPAddedEventType, instance.OIDCIDPAddedEventType})
+ }
+
+ payloadJSON, err := json.Marshal(idpEvent)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ handler.NewCol(IDPRelationalOrgId, orgId),
+ handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive),
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeOIDC),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.OIDCIDPChangedEvent
+ switch e := event.(type) {
+ case *org.OIDCIDPChangedEvent:
+ idpEvent = e.OIDCIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.OIDCIDPChangedEvent:
+ idpEvent = e.OIDCIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y1K82ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPChangedEventType, instance.OIDCIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-L8CQt", "unable to cast to tx executer")
+ }
+ oidc, err := p.idpRepo.GetOIDC(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &oidc.OIDC
+ payloadChanged := reduceOIDCIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalMigratedAzureAD(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idp.OIDCIDPMigratedAzureADEvent
+ switch e := event.(type) {
+ case *org.OIDCIDPMigratedAzureADEvent:
+ idpEvent = e.OIDCIDPMigratedAzureADEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.OIDCIDPMigratedAzureADEvent:
+ idpEvent = e.OIDCIDPMigratedAzureADEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Yb582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPMigratedAzureADEventType, instance.OIDCIDPMigratedAzureADEventType})
+ }
+
+ azureTenant, err := domain.AzureTenantTypeString(idpEvent.Tenant)
+ if err != nil {
+ return nil, err
+ }
+
+ azure := domain.Azure{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ Tenant: azureTenant,
+ IsEmailVerified: idpEvent.IsEmailVerified,
+ }
+
+ payloadJSON, err := json.Marshal(azure)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeAzure),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceOIDCIDPRelationalMigratedGoogle(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idp.OIDCIDPMigratedGoogleEvent
+ switch e := event.(type) {
+ case *org.OIDCIDPMigratedGoogleEvent:
+ idpEvent = e.OIDCIDPMigratedGoogleEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.OIDCIDPMigratedGoogleEvent:
+ idpEvent = e.OIDCIDPMigratedGoogleEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y1502hk", "reduce.wrong.event.type %v", []eventstore.EventType{org.OIDCIDPMigratedGoogleEventType, instance.OIDCIDPMigratedGoogleEventType})
+ }
+
+ google := domain.Google{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(google)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeGoogle),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceJWTIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.JWTIDPAddedEvent
+ switch e := event.(type) {
+ case *org.JWTIDPAddedEvent:
+ idpEvent = e.JWTIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.JWTIDPAddedEvent:
+ idpEvent = e.JWTIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Yopi2s", "reduce.wrong.event.type %v", []eventstore.EventType{org.JWTIDPAddedEventType, instance.JWTIDPAddedEventType})
+ }
+
+ jwt := domain.JWT{
+ JWTEndpoint: idpEvent.JWTEndpoint,
+ Issuer: idpEvent.Issuer,
+ KeysEndpoint: idpEvent.KeysEndpoint,
+ HeaderName: idpEvent.HeaderName,
+ }
+
+ payloadJSON, err := json.Marshal(jwt)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ handler.NewCol(IDPRelationalOrgId, orgId),
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive.String()),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeJWT),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceJWTIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.JWTIDPChangedEvent
+ switch e := event.(type) {
+ case *org.JWTIDPChangedEvent:
+ idpEvent = e.JWTIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.JWTIDPChangedEvent:
+ idpEvent = e.JWTIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-H15j2il", "reduce.wrong.event.type %v", []eventstore.EventType{org.JWTIDPChangedEventType, instance.JWTIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ jwt, err := p.idpRepo.GetJWT(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &jwt.JWT
+ payloadChanged := reduceJWTIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceAzureADIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.AzureADIDPAddedEvent
+ switch e := event.(type) {
+ case *org.AzureADIDPAddedEvent:
+ idpEvent = e.AzureADIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.AzureADIDPAddedEvent:
+ idpEvent = e.AzureADIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y9a022b", "reduce.wrong.event.type %v", []eventstore.EventType{org.AzureADIDPAddedEventType, instance.AzureADIDPAddedEventType})
+ }
+
+ azureTenant, err := domain.AzureTenantTypeString(idpEvent.Tenant)
+ if err != nil {
+ return nil, err
+ }
+
+ azure := domain.Azure{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ Tenant: azureTenant,
+ IsEmailVerified: idpEvent.IsEmailVerified,
+ }
+
+ payloadJSON, err := json.Marshal(azure)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeAzure),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceAzureADIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.AzureADIDPChangedEvent
+ switch e := event.(type) {
+ case *org.AzureADIDPChangedEvent:
+ idpEvent = e.AzureADIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.AzureADIDPChangedEvent:
+ idpEvent = e.AzureADIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YZ5x25s", "reduce.wrong.event.type %v", []eventstore.EventType{org.AzureADIDPChangedEventType, instance.AzureADIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ azure, err := p.idpRepo.GetAzureAD(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &azure.Azure
+ payloadChanged, err := reduceAzureADIDPRelationalChangedColumns(payload, &idpEvent)
+ if err != nil {
+ return err
+ }
+
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitHubIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.GitHubIDPAddedEvent
+ switch e := event.(type) {
+ case *org.GitHubIDPAddedEvent:
+ idpEvent = e.GitHubIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.GitHubIDPAddedEvent:
+ idpEvent = e.GitHubIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-x9a022b", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitHubIDPAddedEventType, instance.GitHubIDPAddedEventType})
+ }
+
+ github := domain.Github{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(github)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeGitHub),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitHubIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.GitHubIDPChangedEvent
+ switch e := event.(type) {
+ case *org.GitHubIDPChangedEvent:
+ idpEvent = e.GitHubIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.GitHubIDPChangedEvent:
+ idpEvent = e.GitHubIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-L1U89ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitHubIDPChangedEventType, instance.GitHubIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ github, err := p.idpRepo.GetGithub(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &github.Github
+ payloadChanged := reduceGitHubIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitHubEnterpriseIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.GitHubEnterpriseIDPAddedEvent
+ switch e := event.(type) {
+ case *org.GitHubEnterpriseIDPAddedEvent:
+ idpEvent = e.GitHubEnterpriseIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.GitHubEnterpriseIDPAddedEvent:
+ idpEvent = e.GitHubEnterpriseIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Yf3g2a", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitHubEnterpriseIDPAddedEventType, instance.GitHubEnterpriseIDPAddedEventType})
+ }
+
+ githubEnterprise := domain.GithubEnterprise{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ AuthorizationEndpoint: idpEvent.AuthorizationEndpoint,
+ TokenEndpoint: idpEvent.TokenEndpoint,
+ UserEndpoint: idpEvent.UserEndpoint,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(githubEnterprise)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []handler.Column{
+ handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ handler.NewCol(IDPRelationalOrgId, orgId),
+ handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive.String()),
+ handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
+ handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeGitHubEnterprise),
+ handler.NewCol(IDPRelationalAllowCreationCol, idpEvent.IsCreationAllowed),
+ handler.NewCol(IDPRelationalAllowLinkingCol, idpEvent.IsLinkingAllowed),
+ handler.NewCol(IDPRelationalAllowAutoCreationCol, idpEvent.IsAutoCreation),
+ handler.NewCol(IDPRelationalAllowAutoUpdateCol, idpEvent.IsAutoUpdate),
+ handler.NewCol(IDPRelationalAllowAutoLinkingCol, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitHubEnterpriseIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.GitHubEnterpriseIDPChangedEvent
+ switch e := event.(type) {
+ case *org.GitHubEnterpriseIDPChangedEvent:
+ idpEvent = e.GitHubEnterpriseIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.GitHubEnterpriseIDPChangedEvent:
+ idpEvent = e.GitHubEnterpriseIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YDg3g", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitHubEnterpriseIDPChangedEventType, instance.GitHubEnterpriseIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ githubEnterprise, err := p.idpRepo.GetGithubEnterprise(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &githubEnterprise.GithubEnterprise
+ payloadChanged := reduceGitHubEnterpriseIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitLabIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.GitLabIDPAddedEvent
+ switch e := event.(type) {
+ case *org.GitLabIDPAddedEvent:
+ idpEvent = e.GitLabIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.GitLabIDPAddedEvent:
+ idpEvent = e.GitLabIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y9a022b", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitLabIDPAddedEventType, instance.GitLabIDPAddedEventType})
+ }
+
+ gitlab := domain.Gitlab{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(gitlab)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeGitLab),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitLabIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.GitLabIDPChangedEvent
+ switch e := event.(type) {
+ case *org.GitLabIDPChangedEvent:
+ idpEvent = e.GitLabIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.GitLabIDPChangedEvent:
+ idpEvent = e.GitLabIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-mT5827b", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitLabIDPChangedEventType, instance.GitLabIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ gitlab, err := p.idpRepo.GetGitlab(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &gitlab.Gitlab
+ payloadChanged := reduceGitLabIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitLabSelfHostedIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.GitLabSelfHostedIDPAddedEvent
+ switch e := event.(type) {
+ case *org.GitLabSelfHostedIDPAddedEvent:
+ idpEvent = e.GitLabSelfHostedIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.GitLabSelfHostedIDPAddedEvent:
+ idpEvent = e.GitLabSelfHostedIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YAF3gw", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitLabSelfHostedIDPAddedEventType, instance.GitLabSelfHostedIDPAddedEventType})
+ }
+
+ gitlabSelfHosting := domain.GitlabSelfHosting{
+ Issuer: idpEvent.Issuer,
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(gitlabSelfHosting)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeGitLabSelfHosted),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGitLabSelfHostedIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.GitLabSelfHostedIDPChangedEvent
+ switch e := event.(type) {
+ case *org.GitLabSelfHostedIDPChangedEvent:
+ idpEvent = e.GitLabSelfHostedIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.GitLabSelfHostedIDPChangedEvent:
+ idpEvent = e.GitLabSelfHostedIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YAf3g2", "reduce.wrong.event.type %v", []eventstore.EventType{org.GitLabSelfHostedIDPChangedEventType, instance.GitLabSelfHostedIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ gitlabSelfHosted, err := p.idpRepo.GetGitlabSelfHosting(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &gitlabSelfHosted.GitlabSelfHosting
+ payloadChanged := reduceGitLabSelfHostedIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGoogleIDPRelationalAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.GoogleIDPAddedEvent
+ switch e := event.(type) {
+ case *org.GoogleIDPAddedEvent:
+ idpEvent = e.GoogleIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.GoogleIDPAddedEvent:
+ idpEvent = e.GoogleIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Yp9ihb", "reduce.wrong.event.type %v", []eventstore.EventType{org.GoogleIDPAddedEventType, instance.GoogleIDPAddedEventType})
+ }
+
+ google := domain.Google{
+ ClientID: idpEvent.ClientID,
+ ClientSecret: idpEvent.ClientSecret,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(google)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeGoogle),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceGoogleIDPRelationalChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.GoogleIDPChangedEvent
+ switch e := event.(type) {
+ case *org.GoogleIDPChangedEvent:
+ idpEvent = e.GoogleIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.GoogleIDPChangedEvent:
+ idpEvent = e.GoogleIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YN58hml", "reduce.wrong.event.type %v", []eventstore.EventType{org.GoogleIDPChangedEventType, instance.GoogleIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ google, err := p.idpRepo.GetGoogle(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &google.Google
+ payloadChanged := reduceGoogleIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceLDAPIDPAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.LDAPIDPAddedEvent
+ switch e := event.(type) {
+ case *org.LDAPIDPAddedEvent:
+ idpEvent = e.LDAPIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.LDAPIDPAddedEvent:
+ idpEvent = e.LDAPIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.LDAPIDPAddedEventType, instance.LDAPIDPAddedEventType})
+ }
+
+ ldap := domain.LDAP{
+ Servers: idpEvent.Servers,
+ StartTLS: idpEvent.StartTLS,
+ BaseDN: idpEvent.BaseDN,
+ BindDN: idpEvent.BindDN,
+ BindPassword: idpEvent.BindPassword,
+ UserBase: idpEvent.UserBase,
+ UserObjectClasses: idpEvent.UserObjectClasses,
+ UserFilters: idpEvent.UserFilters,
+ Timeout: idpEvent.Timeout,
+ LDAPAttributes: domain.LDAPAttributes{
+ IDAttribute: idpEvent.IDAttribute,
+ FirstNameAttribute: idpEvent.FirstNameAttribute,
+ LastNameAttribute: idpEvent.LastNameAttribute,
+ DisplayNameAttribute: idpEvent.DisplayNameAttribute,
+ NickNameAttribute: idpEvent.NickNameAttribute,
+ PreferredUsernameAttribute: idpEvent.PreferredUsernameAttribute,
+ EmailAttribute: idpEvent.EmailAttribute,
+ EmailVerifiedAttribute: idpEvent.EmailVerifiedAttribute,
+ PhoneAttribute: idpEvent.PhoneAttribute,
+ PhoneVerifiedAttribute: idpEvent.PhoneVerifiedAttribute,
+ PreferredLanguageAttribute: idpEvent.PreferredLanguageAttribute,
+ AvatarURLAttribute: idpEvent.AvatarURLAttribute,
+ ProfileAttribute: idpEvent.ProfileAttribute,
+ },
+ }
+
+ payloadJSON, err := json.Marshal(ldap)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeLDAP),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceLDAPIDPChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.LDAPIDPChangedEvent
+ switch e := event.(type) {
+ case *org.LDAPIDPChangedEvent:
+ idpEvent = e.LDAPIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.LDAPIDPChangedEvent:
+ idpEvent = e.LDAPIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.LDAPIDPChangedEventType, instance.LDAPIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ ldap, err := p.idpRepo.GetLDAP(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &ldap.LDAP
+ payloadChanged := reduceLDAPIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceAppleIDPAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.AppleIDPAddedEvent
+ switch e := event.(type) {
+ case *org.AppleIDPAddedEvent:
+ idpEvent = e.AppleIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ case *instance.AppleIDPAddedEvent:
+ idpEvent = e.AppleIDPAddedEvent
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YFvg3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPAddedEventType /*, instance.AppleIDPAddedEventType*/})
+ }
+
+ apple := domain.Apple{
+ ClientID: idpEvent.ClientID,
+ TeamID: idpEvent.TeamID,
+ KeyID: idpEvent.KeyID,
+ PrivateKey: idpEvent.PrivateKey,
+ Scopes: idpEvent.Scopes,
+ }
+
+ payloadJSON, err := json.Marshal(apple)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeApple),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceAppleIDPChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.AppleIDPChangedEvent
+ switch e := event.(type) {
+ case *org.AppleIDPChangedEvent:
+ idpEvent = e.AppleIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.AppleIDPChangedEvent:
+ idpEvent = e.AppleIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-YBez3", "reduce.wrong.event.type %v", []eventstore.EventType{org.AppleIDPChangedEventType /*, instance.AppleIDPChangedEventType*/})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ apple, err := p.idpRepo.GetApple(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &apple.Apple
+ payloadChanged := reduceAppleIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceSAMLIDPAdded(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var idpEvent idp.SAMLIDPAddedEvent
+ switch e := event.(type) {
+ case *org.SAMLIDPAddedEvent:
+ idpEvent = e.SAMLIDPAddedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ 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})
+ }
+
+ saml := domain.SAML{
+ Metadata: idpEvent.Metadata,
+ Key: idpEvent.Key,
+ Certificate: idpEvent.Certificate,
+ Binding: idpEvent.Binding,
+ WithSignedRequest: idpEvent.WithSignedRequest,
+ NameIDFormat: idpEvent.NameIDFormat,
+ TransientMappingAttributeName: idpEvent.TransientMappingAttributeName,
+ SignatureAlgorithm: idpEvent.SignatureAlgorithm,
+ }
+
+ payloadJSON, err := json.Marshal(saml)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler.NewCreateStatement(
+ &idpEvent,
+ []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, domain.IDPTypeSAML),
+ handler.NewCol(IDPTemplateStateCol, 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, func() any {
+ if idpEvent.AutoLinkingOption == internal_domain.AutoLinkingOptionUnspecified {
+ return nil
+ }
+ return domain.IDPAutoLinkingField(idpEvent.AutoLinkingOption)
+ }()),
+ handler.NewCol(IDPRelationalPayloadCol, payloadJSON),
+ handler.NewCol(CreatedAt, idpEvent.CreationDate()),
+ handler.NewCol(UpdatedAt, idpEvent.CreationDate()),
+ },
+ ), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceSAMLIDPChanged(event eventstore.Event) (*handler.Statement, error) {
+ var orgId *string
+ var orgCond handler.Condition
+ var idpEvent idp.SAMLIDPChangedEvent
+ switch e := event.(type) {
+ case *org.SAMLIDPChangedEvent:
+ idpEvent = e.SAMLIDPChangedEvent
+ orgId = &idpEvent.Aggregate().ResourceOwner
+ orgCond = handler.NewCond(IDPRelationalOrgId, orgId)
+ case *instance.SAMLIDPChangedEvent:
+ idpEvent = e.SAMLIDPChangedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Y7c0fii4ad", "reduce.wrong.event.type %v", []eventstore.EventType{org.SAMLIDPChangedEventType, instance.SAMLIDPChangedEventType})
+ }
+
+ return handler.NewStatement(event, func(ctx context.Context, ex handler.Executer, projectionName string) error {
+ tx, ok := ex.(*sql.Tx)
+ if !ok {
+ return zerrors.ThrowInternal(nil, "HANDL-HX6ed", "unable to cast to tx executer")
+ }
+ saml, err := p.idpRepo.GetSAML(ctx, v3_sql.SQLTx(tx), p.idpRepo.IDCondition(idpEvent.ID), idpEvent.Agg.InstanceID, orgId)
+ if err != nil {
+ return err
+ }
+
+ columns := reduceIDPRelationalChangedTemplateColumns(idpEvent.Name, idpEvent.OptionChanges)
+
+ payload := &saml.SAML
+ payloadChanged := reduceSAMLIDPRelationalChangedColumns(payload, &idpEvent)
+ if payloadChanged {
+ payloadJSON, err := json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ columns = append(columns, handler.NewCol(IDPRelationalPayloadCol, payloadJSON))
+ }
+
+ columns = append(columns, handler.NewCol(UpdatedAt, idpEvent.CreationDate()))
+
+ return handler.NewUpdateStatement(
+ &idpEvent,
+ columns,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ).Execute(ctx, ex, projectionName)
+
+ }), nil
+}
+
+func (p *idpTemplateRelationalProjection) reduceIDPRemoved(event eventstore.Event) (*handler.Statement, error) {
+ var orgCond handler.Condition
+ var idpEvent idp.RemovedEvent
+ switch e := event.(type) {
+ case *org.IDPRemovedEvent:
+ idpEvent = e.RemovedEvent
+ orgCond = handler.NewCond(IDPRelationalOrgId, idpEvent.Aggregate().ResourceOwner)
+ case *instance.IDPRemovedEvent:
+ idpEvent = e.RemovedEvent
+ orgCond = handler.NewIsNullCond((IDPRelationalOrgId))
+ default:
+ return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Ybcvwin2", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPRemovedEventType, instance.IDPRemovedEventType})
+ }
+
+ return handler.NewDeleteStatement(
+ &idpEvent,
+ []handler.Condition{
+ handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
+ handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
+ orgCond,
+ },
+ ), nil
+}
+
+func reduceIDPRelationalChangedTemplateColumns(name *string, optionChanges idp.OptionChanges) []handler.Column {
+ cols := make([]handler.Column, 0, 8)
+ if name != nil {
+ cols = append(cols, handler.NewCol(IDPTemplateNameCol, *name))
+ }
+ if optionChanges.IsCreationAllowed != nil {
+ cols = append(cols, handler.NewCol(IDPRelationalAllowCreationCol, *optionChanges.IsCreationAllowed))
+ }
+ if optionChanges.IsLinkingAllowed != nil {
+ cols = append(cols, handler.NewCol(IDPRelationalAllowLinkingCol, *optionChanges.IsLinkingAllowed))
+ }
+ if optionChanges.IsAutoCreation != nil {
+ cols = append(cols, handler.NewCol(IDPRelationalAllowAutoCreationCol, *optionChanges.IsAutoCreation))
+ }
+ if optionChanges.IsAutoUpdate != nil {
+ cols = append(cols, handler.NewCol(IDPRelationalAllowAutoUpdateCol, *optionChanges.IsAutoUpdate))
+ }
+ if optionChanges.AutoLinkingOption != nil && *optionChanges.AutoLinkingOption != internal_domain.AutoLinkingOptionUnspecified {
+ cols = append(cols, handler.NewCol(IDPRelationalAllowAutoLinkingCol, domain.IDPAutoLinkingField(*optionChanges.AutoLinkingOption)))
+ }
+
+ return cols
+}
+
+func reduceOAuthIDPRelationalChangedColumns(payload *domain.OAuth, idpEvent *idp.OAuthIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.AuthorizationEndpoint != nil {
+ payloadChange = true
+ payload.AuthorizationEndpoint = *idpEvent.AuthorizationEndpoint
+ }
+ if idpEvent.TokenEndpoint != nil {
+ payloadChange = true
+ payload.TokenEndpoint = *idpEvent.TokenEndpoint
+ }
+ if idpEvent.UserEndpoint != nil {
+ payloadChange = true
+ payload.UserEndpoint = *idpEvent.UserEndpoint
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ if idpEvent.IDAttribute != nil {
+ payloadChange = true
+ payload.IDAttribute = *idpEvent.IDAttribute
+ }
+ if idpEvent.UsePKCE != nil {
+ payloadChange = true
+ payload.UsePKCE = *idpEvent.UsePKCE
+ }
+ return payloadChange
+}
+
+func reduceOIDCIDPRelationalChangedColumns(payload *domain.OIDC, idpEvent *idp.OIDCIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Issuer != nil {
+ payloadChange = true
+ payload.Issuer = *idpEvent.Issuer
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ if idpEvent.IsIDTokenMapping != nil {
+ payloadChange = true
+ payload.IsIDTokenMapping = *idpEvent.IsIDTokenMapping
+ }
+ if idpEvent.UsePKCE != nil {
+ payloadChange = true
+ payload.UsePKCE = *idpEvent.UsePKCE
+ }
+ return payloadChange
+}
+
+func reduceJWTIDPRelationalChangedColumns(payload *domain.JWT, idpEvent *idp.JWTIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.JWTEndpoint != nil {
+ payloadChange = true
+ payload.JWTEndpoint = *idpEvent.JWTEndpoint
+ }
+ if idpEvent.KeysEndpoint != nil {
+ payloadChange = true
+ payload.KeysEndpoint = *idpEvent.KeysEndpoint
+ }
+ if idpEvent.HeaderName != nil {
+ payloadChange = true
+ payload.HeaderName = *idpEvent.HeaderName
+ }
+ if idpEvent.Issuer != nil {
+ payloadChange = true
+ payload.Issuer = *idpEvent.Issuer
+ }
+ return payloadChange
+}
+
+func reduceAzureADIDPRelationalChangedColumns(payload *domain.Azure, idpEvent *idp.AzureADIDPChangedEvent) (bool, error) {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ if idpEvent.Tenant != nil {
+ payloadChange = true
+
+ azureTenant, err := domain.AzureTenantTypeString(*idpEvent.Tenant)
+ if err != nil {
+ return false, err
+ }
+
+ payload.Tenant = azureTenant
+ }
+ if idpEvent.IsEmailVerified != nil {
+ payloadChange = true
+ payload.IsEmailVerified = *idpEvent.IsEmailVerified
+ }
+ return payloadChange, nil
+}
+
+func reduceGitHubIDPRelationalChangedColumns(payload *domain.Github, idpEvent *idp.GitHubIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ return payloadChange
+}
+
+func reduceGitHubEnterpriseIDPRelationalChangedColumns(payload *domain.GithubEnterprise, idpEvent *idp.GitHubEnterpriseIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.AuthorizationEndpoint != nil {
+ payloadChange = true
+ payload.AuthorizationEndpoint = *idpEvent.AuthorizationEndpoint
+ }
+ if idpEvent.TokenEndpoint != nil {
+ payloadChange = true
+ payload.TokenEndpoint = *idpEvent.TokenEndpoint
+ }
+ if idpEvent.UserEndpoint != nil {
+ payloadChange = true
+ payload.UserEndpoint = *idpEvent.UserEndpoint
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ return payloadChange
+}
+
+func reduceGitLabIDPRelationalChangedColumns(payload *domain.Gitlab, idpEvent *idp.GitLabIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ return payloadChange
+}
+
+func reduceGitLabSelfHostedIDPRelationalChangedColumns(payload *domain.GitlabSelfHosting, idpEvent *idp.GitLabSelfHostedIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Issuer != nil {
+ payloadChange = true
+ payload.Issuer = *idpEvent.Issuer
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ return payloadChange
+}
+
+func reduceGoogleIDPRelationalChangedColumns(payload *domain.Google, idpEvent *idp.GoogleIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.ClientID != nil {
+ payloadChange = true
+ payload.ClientID = *idpEvent.ClientID
+ }
+ if idpEvent.ClientSecret != nil {
+ payloadChange = true
+ payload.ClientSecret = idpEvent.ClientSecret
+ }
+ if idpEvent.Scopes != nil {
+ payloadChange = true
+ payload.Scopes = idpEvent.Scopes
+ }
+ return payloadChange
+}
+
+func reduceLDAPIDPRelationalChangedColumns(payload *domain.LDAP, idpEvent *idp.LDAPIDPChangedEvent) bool {
+ payloadChange := false
+ if idpEvent.Servers != nil {
+ payloadChange = true
+ payload.Servers = idpEvent.Servers
+ }
+ if idpEvent.StartTLS != nil {
+ payloadChange = true
+ payload.StartTLS = *idpEvent.StartTLS
+ }
+ if idpEvent.BaseDN != nil {
+ payloadChange = true
+ payload.BaseDN = *idpEvent.BaseDN
+ }
+ if idpEvent.BindDN != nil {
+ payloadChange = true
+ payload.BindDN = *idpEvent.BindDN
+ }
+ if idpEvent.BindPassword != nil {
+ payloadChange = true
+ payload.BindPassword = idpEvent.BindPassword
+ }
+ if idpEvent.UserBase != nil {
+ payloadChange = true
+ payload.UserBase = *idpEvent.UserBase
+ }
+ if idpEvent.UserObjectClasses != nil {
+ payloadChange = true
+ payload.UserObjectClasses = idpEvent.UserObjectClasses
+ }
+ if idpEvent.UserFilters != nil {
+ payloadChange = true
+ payload.UserFilters = idpEvent.UserFilters
+ }
+ if idpEvent.Timeout != nil {
+ payloadChange = true
+ payload.Timeout = *idpEvent.Timeout
+ }
+ if idpEvent.RootCA != nil {
+ payloadChange = true
+ payload.RootCA = idpEvent.RootCA
+ }
+ if idpEvent.IDAttribute != nil {
+ payloadChange = true
+ payload.IDAttribute = *idpEvent.IDAttribute
+ }
+ if idpEvent.FirstNameAttribute != nil {
+ payloadChange = true
+ payload.FirstNameAttribute = *idpEvent.FirstNameAttribute
+ }
+ if idpEvent.LastNameAttribute != nil {
+ payloadChange = true
+ payload.LastNameAttribute = *idpEvent.LastNameAttribute
+ }
+ if idpEvent.DisplayNameAttribute != nil {
+ payloadChange = true
+ payload.DisplayNameAttribute = *idpEvent.DisplayNameAttribute
+ }
+ if idpEvent.NickNameAttribute != nil {
+ payloadChange = true
+ payload.NickNameAttribute = *idpEvent.NickNameAttribute
+ }
+ if idpEvent.PreferredUsernameAttribute != nil {
+ payloadChange = true
+ payload.PreferredUsernameAttribute = *idpEvent.PreferredUsernameAttribute
+ }
+ if idpEvent.EmailAttribute != nil {
+ payloadChange = true
+ payload.EmailAttribute = *idpEvent.EmailAttribute
+ }
+ if idpEvent.EmailVerifiedAttribute != nil {
+ payloadChange = true
+ payload.EmailVerifiedAttribute = *idpEvent.EmailVerifiedAttribute
+ }
+ if idpEvent.PhoneAttribute != nil {
+ payloadChange = true
+ payload.PhoneAttribute = *idpEvent.PhoneAttribute
+ }
+ if idpEvent.PhoneVerifiedAttribute != nil {
+ payloadChange = true
+ payload.PhoneVerifiedAttribute = *idpEvent.PhoneVerifiedAttribute
+ }
+ if idpEvent.PreferredLanguageAttribute != nil {
+ payloadChange = true
+ payload.PreferredLanguageAttribute = *idpEvent.PreferredLanguageAttribute
+ }
+ if idpEvent.AvatarURLAttribute != nil {
+ payloadChange = true
+ payload.AvatarURLAttribute = *idpEvent.AvatarURLAttribute
+ }
+ if idpEvent.ProfileAttribute != nil {
+ payloadChange = true
+ payload.ProfileAttribute = *idpEvent.ProfileAttribute
+ }
+ 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
+ }
+ if idpEvent.Key != nil {
+ payloadChange = true
+ payload.Key = idpEvent.Key
+ }
+ if idpEvent.Certificate != nil {
+ payloadChange = true
+ payload.Certificate = idpEvent.Certificate
+ }
+ if idpEvent.Binding != nil {
+ payloadChange = true
+ payload.Binding = *idpEvent.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
+ }
+ if idpEvent.SignatureAlgorithm != nil {
+ payloadChange = true
+ payload.SignatureAlgorithm = *idpEvent.SignatureAlgorithm
+ }
+ return payloadChange
+}
diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go
index cddf65114f8..0ee8096b1a8 100644
--- a/internal/query/projection/projection.go
+++ b/internal/query/projection/projection.go
@@ -93,6 +93,7 @@ var (
OrganizationRelationalProjection *handler.Handler
InstanceDomainRelationalProjection *handler.Handler
OrganizationDomainRelationalProjection *handler.Handler
+ IDPTemplateRelationalProjection *handler.Handler
ProjectGrantFields *handler.FieldHandler
OrgDomainVerifiedFields *handler.FieldHandler
@@ -208,6 +209,7 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore,
OrganizationRelationalProjection = newOrgRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organizations_relational"]))
InstanceDomainRelationalProjection = newInstanceDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["instance_domains_relational"]))
OrganizationDomainRelationalProjection = newOrgDomainRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["organization_domains_relational"]))
+ IDPTemplateRelationalProjection = newIDPTemplateRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates_relational"]))
newProjectionsList()
newFieldsList()
@@ -395,5 +397,6 @@ func newProjectionsList() {
OrganizationRelationalProjection,
InstanceDomainRelationalProjection,
OrganizationDomainRelationalProjection,
+ IDPTemplateRelationalProjection,
}
}