diff --git a/backend/v3/domain/idp_intent.go b/backend/v3/domain/idp_intent.go new file mode 100644 index 000000000..43c2210ae --- /dev/null +++ b/backend/v3/domain/idp_intent.go @@ -0,0 +1,174 @@ +package domain + +import ( + "context" + "net/url" + "time" + + "github.com/zitadel/zitadel/backend/v3/storage/database" +) + +//go:generate enumer -type IDPIntentState -transform lower -trimprefix IDPIntentState -sql +type IDPIntentState uint8 + +const ( + IDPIntentStateStarted IDPIntentState = iota + IDPIntentStateSucceeded + IDPIntentStateFailed +) + +type IDPIntent struct { + ID string `json:"id,omitempty" db:"id"` + InstanceID string `json:"instance_id,omitempty" db:"instance_id"` + State IDPIntentState `json:"state" db:"state"` + SuccessURL *url.URL `json:"success_url,omitempty" db:"success_url"` + FailureURL *url.URL `json:"failure_url,omitempty" db:"failure_url"` + CreatedAt time.Time `json:"created_at,omitzero" db:"created_at"` + UpdatedAt time.Time `json:"updated_at,omitzero" db:"updated_at"` + IDPID string `json:"idp_id,omitempty" db:"idp_id"` + IDPArguments map[string]any `json:"idp_arguments,omitempty" db:"idp_arguments"` + IDPUser []byte `json:"idp_user,omitempty" db:"idp_user"` + IDPUserID string `json:"idp_user_id,omitempty" db:"idp_user_id"` + IDPUsername string `json:"idp_username,omitempty" db:"idp_username"` + UserID string `json:"user_id,omitempty" db:"user_id"` + IDPAccessToken []byte `json:"idp_access_token,omitempty" db:"idp_access_token"` + IDPIDToken string `json:"idp_id_token,omitempty" db:"idp_id_token"` + EntryAttributes map[string][]string `json:"idp_entry_attributes,omitempty" db:"idp_entry_attributes"` + RequestID string `json:"request_id,omitempty" db:"request_id"` + Assertion []byte `json:"assertion,omitempty" db:"assertion"` + SucceededAt *time.Time `json:"succeeded_at,omitzero" db:"succeeded_at"` + FailReason string `json:"fail_reason,omitempty" db:"fail_reason"` + FailedAt *time.Time `json:"failed_at,omitzero" db:"failed_at"` + ExpiresAt *time.Time `json:"expires_at,omitzero" db:"expires_at"` +} + +// idpIntentColumns defines all the columns of the identity_provider_intents table. +type idpIntentColumns interface { + // IDColumn returns the column for the field id + IDColumn() database.Column + // InstanceIDColumn returns the column for the field instance_id + InstanceIDColumn() database.Column + // StateColumn returns the column for the field state + StateColumn() database.Column + // SuccessURLColumn returns the column for the field success_url + SuccessURLColumn() database.Column + // FailureURLColumn returns the column for the field failure_url + FailureURLColumn() database.Column + // CreatedAtColumn returns the column for the field created_at + CreatedAtColumn() database.Column + // UpdatedAtColumn returns the column for the field updated_at + UpdatedAtColumn() database.Column + // IDPIDColumn returns the column for the field idp_id + IDPIDColumn() database.Column + // IDPArgumentsColumn returns the column for the field idp_arguments + IDPArgumentsColumn() database.Column + // IDPUserColumn returns the column for the field idp_user + IDPUserColumn() database.Column + // IDPUserIDColumn returns the column for the field idp_user_id + IDPUserIDColumn() database.Column + // IDPUsernameColumn returns the column for the field idp_username + IDPUsernameColumn() database.Column + // UserIDColumn returns the column for the field user_id + UserIDColumn() database.Column + // IDPAccessTokenColumn returns the column for the field idp_access_token + IDPAccessTokenColumn() database.Column + // IDPIDTokenColumn returns the column for the field idp_id_token + IDPIDTokenColumn() database.Column + // IDPEntryAttributesColumn returns the column for the field idp_entry_attributes + IDPEntryAttributesColumn() database.Column + // RequestIDColumn returns the column for the field request_id + RequestIDColumn() database.Column + // AssertionColumn returns the column for the field assertion + AssertionColumn() database.Column + // SucceededAtColumn returns the column for the field succeeded_at + SucceededAtColumn() database.Column + // FailReasonColumn returns the column for the field fail_reason + FailReasonColumn() database.Column + // FailedAtColumn returns the column for the field failed_at + FailedAtColumn() database.Column + // ExpiresAtColumn returns the column for the field expires_at + ExpiresAtColumn() database.Column +} + +type idpIntentConditions interface { + // PrimaryKeyCondition returns a filter on the primary key fields. + PrimaryKeyCondition(instanceID, id string) database.Condition + // IDCondition returns an equal filter on the ID + IDCondition(id string) database.Condition + // InstanceIDCondition returns an equal filter on the InstanceID + InstanceIDCondition(instanceID string) database.Condition + // StateCondition returns an equal filter on the State + StateCondition(state IDPIntentState) database.Condition + // IDPIDCondition returns an equal filter on the IDPID + IDPIDCondition(idpID string) database.Condition + // IDPUserIDCondition returns an equal filter on the IDPUserID + IDPUserIDCondition(idpUserID string) database.Condition + // IDPUsernameCondition returns an equal filter on the IDPUsername + IDPUsernameCondition(idpUsername string) database.Condition + // UserIDCondition returns an equal filter on the UserID + UserIDCondition(userID string) database.Condition + // RequestIDCondition returns an equal filter on the RequestID + RequestIDCondition(requestID string) database.Condition + // CreatedAtCondition returns a filter on the created at field. + CreatedAtCondition(op database.NumberOperation, createdAt time.Time) database.Condition + // UpdatedAtCondition returns a filter on the updated at field. + UpdatedAtCondition(op database.NumberOperation, updatedAt time.Time) database.Condition +} + +type idpIntentChanges interface { + // SetState sets the state of the IDP intent + SetState(state IDPIntentState) database.Change + // SetSuccessURL sets the successURL of the IDP intent + SetSuccessURL(successURL url.URL) database.Change + // SetFailureURL sets the failureURL of the IDP intent + SetFailureURL(failureURL url.URL) database.Change + // SetIDPID sets the idpID of the IDP intent + SetIDPID(idpID string) database.Change + // SetIDPArguments sets the idpArguments of the IDP intent + SetIDPArguments(idpArguments []byte) database.Change + // SetIDPUser sets the idpUser of the IDP intent + SetIDPUser(idpUser []byte) database.Change + // SetIDPUserID sets the idpUserID of the IDP intent + SetIDPUserID(idpUserID string) database.Change + // SetIDPUsername sets the idpUsername of the IDP intent + SetIDPUsername(idpUsername string) database.Change + // SetUserID sets the userID of the IDP intent + SetUserID(userID string) database.Change + // SetIDPAccessToken sets the idpAccessToken of the IDP intent + SetIDPAccessToken(idpAccessToken []byte) database.Change + // SetIDPIDToken sets the idpIDToken of the IDP intent + SetIDPIDToken(idpIDToken string) database.Change + // SetIDPEntryAttributes sets the idpEntryAttributes of the IDP intent + SetIDPEntryAttributes(idpEntryAttributes []byte) database.Change + // SetRequestID sets the requestID of the IDP intent + SetRequestID(requestID string) database.Change + // SetAssertion sets the assertion of the IDP intent + SetAssertion(assertion []byte) database.Change + // SetFailReason sets the fail reason of the IDP intent + SetFailReason(reason string) database.Change + // SetExpiresAt sets the expiration of the IDP intent + SetExpiresAt(expiration time.Time) database.Change + // SetSucceededAt sets the succededAt time of the IDP intent + SetSucceededAt(succeededAt time.Time) database.Change + // SetFailedAt sets the failedAt time of the IDP intent + SetFailedAt(failedAt time.Time) database.Change +} + +//go:generate mockgen -typed -package domainmock -destination ./mock/idp_intent.mock.go . IDPIntentRepository +type IDPIntentRepository interface { + Repository + + idpIntentColumns + idpIntentConditions + idpIntentChanges + + // Get returns an idp intent based on the given condition. + Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*IDPIntent, error) + // Create creates a new idp intent. + Create(ctx context.Context, client database.QueryExecutor, intent *IDPIntent) error + // Update one or more existing idp intents. + // The condition must include at least the instanceID of the idp intent to update. + Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) + // Delete removes idp intents based on the given condition. + Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) +} diff --git a/backend/v3/domain/idpintentstate_enumer.go b/backend/v3/domain/idpintentstate_enumer.go new file mode 100644 index 000000000..3b9e1ae6c --- /dev/null +++ b/backend/v3/domain/idpintentstate_enumer.go @@ -0,0 +1,113 @@ +// Code generated by "enumer -type IDPIntentState -transform lower -trimprefix IDPIntentState -sql"; DO NOT EDIT. + +package domain + +import ( + "database/sql/driver" + "fmt" + "strings" +) + +const _IDPIntentStateName = "startedsucceededfailed" + +var _IDPIntentStateIndex = [...]uint8{0, 7, 16, 22} + +const _IDPIntentStateLowerName = "startedsucceededfailed" + +func (i IDPIntentState) String() string { + if i >= IDPIntentState(len(_IDPIntentStateIndex)-1) { + return fmt.Sprintf("IDPIntentState(%d)", i) + } + return _IDPIntentStateName[_IDPIntentStateIndex[i]:_IDPIntentStateIndex[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 _IDPIntentStateNoOp() { + var x [1]struct{} + _ = x[IDPIntentStateStarted-(0)] + _ = x[IDPIntentStateSucceeded-(1)] + _ = x[IDPIntentStateFailed-(2)] +} + +var _IDPIntentStateValues = []IDPIntentState{IDPIntentStateStarted, IDPIntentStateSucceeded, IDPIntentStateFailed} + +var _IDPIntentStateNameToValueMap = map[string]IDPIntentState{ + _IDPIntentStateName[0:7]: IDPIntentStateStarted, + _IDPIntentStateLowerName[0:7]: IDPIntentStateStarted, + _IDPIntentStateName[7:16]: IDPIntentStateSucceeded, + _IDPIntentStateLowerName[7:16]: IDPIntentStateSucceeded, + _IDPIntentStateName[16:22]: IDPIntentStateFailed, + _IDPIntentStateLowerName[16:22]: IDPIntentStateFailed, +} + +var _IDPIntentStateNames = []string{ + _IDPIntentStateName[0:7], + _IDPIntentStateName[7:16], + _IDPIntentStateName[16:22], +} + +// IDPIntentStateString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func IDPIntentStateString(s string) (IDPIntentState, error) { + if val, ok := _IDPIntentStateNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _IDPIntentStateNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to IDPIntentState values", s) +} + +// IDPIntentStateValues returns all values of the enum +func IDPIntentStateValues() []IDPIntentState { + return _IDPIntentStateValues +} + +// IDPIntentStateStrings returns a slice of all String values of the enum +func IDPIntentStateStrings() []string { + strs := make([]string, len(_IDPIntentStateNames)) + copy(strs, _IDPIntentStateNames) + return strs +} + +// IsAIDPIntentState returns "true" if the value is listed in the enum definition. "false" otherwise +func (i IDPIntentState) IsAIDPIntentState() bool { + for _, v := range _IDPIntentStateValues { + if i == v { + return true + } + } + return false +} + +func (i IDPIntentState) Value() (driver.Value, error) { + return i.String(), nil +} + +func (i *IDPIntentState) 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 IDPIntentState: %[1]T(%[1]v)", value) + } + + val, err := IDPIntentStateString(str) + if err != nil { + return err + } + + *i = val + return nil +} diff --git a/backend/v3/domain/mock/idp_intent.mock.go b/backend/v3/domain/mock/idp_intent.mock.go new file mode 100644 index 000000000..07aba9cbd --- /dev/null +++ b/backend/v3/domain/mock/idp_intent.mock.go @@ -0,0 +1,2186 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/zitadel/zitadel/backend/v3/domain (interfaces: IDPIntentRepository) +// +// Generated by this command: +// +// mockgen -typed -package domainmock -destination ./mock/idp_intent.mock.go . IDPIntentRepository +// + +// Package domainmock is a generated GoMock package. +package domainmock + +import ( + context "context" + url "net/url" + reflect "reflect" + time "time" + + domain "github.com/zitadel/zitadel/backend/v3/domain" + database "github.com/zitadel/zitadel/backend/v3/storage/database" + gomock "go.uber.org/mock/gomock" +) + +// MockIDPIntentRepository is a mock of IDPIntentRepository interface. +type MockIDPIntentRepository struct { + ctrl *gomock.Controller + recorder *MockIDPIntentRepositoryMockRecorder + isgomock struct{} +} + +// MockIDPIntentRepositoryMockRecorder is the mock recorder for MockIDPIntentRepository. +type MockIDPIntentRepositoryMockRecorder struct { + mock *MockIDPIntentRepository +} + +// NewMockIDPIntentRepository creates a new mock instance. +func NewMockIDPIntentRepository(ctrl *gomock.Controller) *MockIDPIntentRepository { + mock := &MockIDPIntentRepository{ctrl: ctrl} + mock.recorder = &MockIDPIntentRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockIDPIntentRepository) EXPECT() *MockIDPIntentRepositoryMockRecorder { + return m.recorder +} + +// AssertionColumn mocks base method. +func (m *MockIDPIntentRepository) AssertionColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AssertionColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// AssertionColumn indicates an expected call of AssertionColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) AssertionColumn() *MockIDPIntentRepositoryAssertionColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssertionColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).AssertionColumn)) + return &MockIDPIntentRepositoryAssertionColumnCall{Call: call} +} + +// MockIDPIntentRepositoryAssertionColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryAssertionColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryAssertionColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryAssertionColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryAssertionColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryAssertionColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryAssertionColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryAssertionColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Create mocks base method. +func (m *MockIDPIntentRepository) Create(ctx context.Context, client database.QueryExecutor, intent *domain.IDPIntent) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, client, intent) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockIDPIntentRepositoryMockRecorder) Create(ctx, client, intent any) *MockIDPIntentRepositoryCreateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockIDPIntentRepository)(nil).Create), ctx, client, intent) + return &MockIDPIntentRepositoryCreateCall{Call: call} +} + +// MockIDPIntentRepositoryCreateCall wrap *gomock.Call +type MockIDPIntentRepositoryCreateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryCreateCall) Return(arg0 error) *MockIDPIntentRepositoryCreateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryCreateCall) Do(f func(context.Context, database.QueryExecutor, *domain.IDPIntent) error) *MockIDPIntentRepositoryCreateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryCreateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, *domain.IDPIntent) error) *MockIDPIntentRepositoryCreateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CreatedAtColumn mocks base method. +func (m *MockIDPIntentRepository) CreatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// CreatedAtColumn indicates an expected call of CreatedAtColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) CreatedAtColumn() *MockIDPIntentRepositoryCreatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).CreatedAtColumn)) + return &MockIDPIntentRepositoryCreatedAtColumnCall{Call: call} +} + +// MockIDPIntentRepositoryCreatedAtColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryCreatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryCreatedAtColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryCreatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryCreatedAtColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryCreatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryCreatedAtColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryCreatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// CreatedAtCondition mocks base method. +func (m *MockIDPIntentRepository) CreatedAtCondition(op database.NumberOperation, createdAt time.Time) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatedAtCondition", op, createdAt) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// CreatedAtCondition indicates an expected call of CreatedAtCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) CreatedAtCondition(op, createdAt any) *MockIDPIntentRepositoryCreatedAtConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatedAtCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).CreatedAtCondition), op, createdAt) + return &MockIDPIntentRepositoryCreatedAtConditionCall{Call: call} +} + +// MockIDPIntentRepositoryCreatedAtConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryCreatedAtConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryCreatedAtConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryCreatedAtConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryCreatedAtConditionCall) Do(f func(database.NumberOperation, time.Time) database.Condition) *MockIDPIntentRepositoryCreatedAtConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryCreatedAtConditionCall) DoAndReturn(f func(database.NumberOperation, time.Time) database.Condition) *MockIDPIntentRepositoryCreatedAtConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Delete mocks base method. +func (m *MockIDPIntentRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, client, condition) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockIDPIntentRepositoryMockRecorder) Delete(ctx, client, condition any) *MockIDPIntentRepositoryDeleteCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockIDPIntentRepository)(nil).Delete), ctx, client, condition) + return &MockIDPIntentRepositoryDeleteCall{Call: call} +} + +// MockIDPIntentRepositoryDeleteCall wrap *gomock.Call +type MockIDPIntentRepositoryDeleteCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryDeleteCall) Return(arg0 int64, arg1 error) *MockIDPIntentRepositoryDeleteCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryDeleteCall) Do(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockIDPIntentRepositoryDeleteCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryDeleteCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition) (int64, error)) *MockIDPIntentRepositoryDeleteCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// ExpiresAtColumn mocks base method. +func (m *MockIDPIntentRepository) ExpiresAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExpiresAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// ExpiresAtColumn indicates an expected call of ExpiresAtColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) ExpiresAtColumn() *MockIDPIntentRepositoryExpiresAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExpiresAtColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).ExpiresAtColumn)) + return &MockIDPIntentRepositoryExpiresAtColumnCall{Call: call} +} + +// MockIDPIntentRepositoryExpiresAtColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryExpiresAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryExpiresAtColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryExpiresAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryExpiresAtColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryExpiresAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryExpiresAtColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryExpiresAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FailReasonColumn mocks base method. +func (m *MockIDPIntentRepository) FailReasonColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FailReasonColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// FailReasonColumn indicates an expected call of FailReasonColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) FailReasonColumn() *MockIDPIntentRepositoryFailReasonColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FailReasonColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).FailReasonColumn)) + return &MockIDPIntentRepositoryFailReasonColumnCall{Call: call} +} + +// MockIDPIntentRepositoryFailReasonColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryFailReasonColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryFailReasonColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryFailReasonColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryFailReasonColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryFailReasonColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryFailReasonColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryFailReasonColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FailedAtColumn mocks base method. +func (m *MockIDPIntentRepository) FailedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FailedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// FailedAtColumn indicates an expected call of FailedAtColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) FailedAtColumn() *MockIDPIntentRepositoryFailedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FailedAtColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).FailedAtColumn)) + return &MockIDPIntentRepositoryFailedAtColumnCall{Call: call} +} + +// MockIDPIntentRepositoryFailedAtColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryFailedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryFailedAtColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryFailedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryFailedAtColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryFailedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryFailedAtColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryFailedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// FailureURLColumn mocks base method. +func (m *MockIDPIntentRepository) FailureURLColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FailureURLColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// FailureURLColumn indicates an expected call of FailureURLColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) FailureURLColumn() *MockIDPIntentRepositoryFailureURLColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FailureURLColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).FailureURLColumn)) + return &MockIDPIntentRepositoryFailureURLColumnCall{Call: call} +} + +// MockIDPIntentRepositoryFailureURLColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryFailureURLColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryFailureURLColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryFailureURLColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryFailureURLColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryFailureURLColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryFailureURLColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryFailureURLColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Get mocks base method. +func (m *MockIDPIntentRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.IDPIntent, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Get", varargs...) + ret0, _ := ret[0].(*domain.IDPIntent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockIDPIntentRepositoryMockRecorder) Get(ctx, client any, opts ...any) *MockIDPIntentRepositoryGetCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client}, opts...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockIDPIntentRepository)(nil).Get), varargs...) + return &MockIDPIntentRepositoryGetCall{Call: call} +} + +// MockIDPIntentRepositoryGetCall wrap *gomock.Call +type MockIDPIntentRepositoryGetCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryGetCall) Return(arg0 *domain.IDPIntent, arg1 error) *MockIDPIntentRepositoryGetCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryGetCall) Do(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.IDPIntent, error)) *MockIDPIntentRepositoryGetCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryGetCall) DoAndReturn(f func(context.Context, database.QueryExecutor, ...database.QueryOption) (*domain.IDPIntent, error)) *MockIDPIntentRepositoryGetCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDColumn mocks base method. +func (m *MockIDPIntentRepository) IDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDColumn indicates an expected call of IDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDColumn() *MockIDPIntentRepositoryIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDColumn)) + return &MockIDPIntentRepositoryIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDCondition mocks base method. +func (m *MockIDPIntentRepository) IDCondition(id string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDCondition", id) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDCondition indicates an expected call of IDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) IDCondition(id any) *MockIDPIntentRepositoryIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDCondition), id) + return &MockIDPIntentRepositoryIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPAccessTokenColumn mocks base method. +func (m *MockIDPIntentRepository) IDPAccessTokenColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPAccessTokenColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPAccessTokenColumn indicates an expected call of IDPAccessTokenColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPAccessTokenColumn() *MockIDPIntentRepositoryIDPAccessTokenColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPAccessTokenColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPAccessTokenColumn)) + return &MockIDPIntentRepositoryIDPAccessTokenColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPAccessTokenColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPAccessTokenColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPAccessTokenColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPAccessTokenColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPAccessTokenColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPAccessTokenColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPAccessTokenColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPAccessTokenColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPArgumentsColumn mocks base method. +func (m *MockIDPIntentRepository) IDPArgumentsColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPArgumentsColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPArgumentsColumn indicates an expected call of IDPArgumentsColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPArgumentsColumn() *MockIDPIntentRepositoryIDPArgumentsColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPArgumentsColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPArgumentsColumn)) + return &MockIDPIntentRepositoryIDPArgumentsColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPArgumentsColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPArgumentsColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPArgumentsColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPArgumentsColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPArgumentsColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPArgumentsColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPArgumentsColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPArgumentsColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPEntryAttributesColumn mocks base method. +func (m *MockIDPIntentRepository) IDPEntryAttributesColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPEntryAttributesColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPEntryAttributesColumn indicates an expected call of IDPEntryAttributesColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPEntryAttributesColumn() *MockIDPIntentRepositoryIDPEntryAttributesColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPEntryAttributesColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPEntryAttributesColumn)) + return &MockIDPIntentRepositoryIDPEntryAttributesColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPEntryAttributesColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPEntryAttributesColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPEntryAttributesColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPEntryAttributesColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPEntryAttributesColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPEntryAttributesColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPEntryAttributesColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPEntryAttributesColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPIDColumn mocks base method. +func (m *MockIDPIntentRepository) IDPIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPIDColumn indicates an expected call of IDPIDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPIDColumn() *MockIDPIntentRepositoryIDPIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPIDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPIDColumn)) + return &MockIDPIntentRepositoryIDPIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPIDCondition mocks base method. +func (m *MockIDPIntentRepository) IDPIDCondition(idpID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPIDCondition", idpID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDPIDCondition indicates an expected call of IDPIDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPIDCondition(idpID any) *MockIDPIntentRepositoryIDPIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPIDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPIDCondition), idpID) + return &MockIDPIntentRepositoryIDPIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryIDPIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryIDPIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryIDPIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryIDPIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPIDTokenColumn mocks base method. +func (m *MockIDPIntentRepository) IDPIDTokenColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPIDTokenColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPIDTokenColumn indicates an expected call of IDPIDTokenColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPIDTokenColumn() *MockIDPIntentRepositoryIDPIDTokenColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPIDTokenColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPIDTokenColumn)) + return &MockIDPIntentRepositoryIDPIDTokenColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPIDTokenColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPIDTokenColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPIDTokenColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPIDTokenColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPIDTokenColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPIDTokenColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPIDTokenColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPIDTokenColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPUserColumn mocks base method. +func (m *MockIDPIntentRepository) IDPUserColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPUserColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPUserColumn indicates an expected call of IDPUserColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPUserColumn() *MockIDPIntentRepositoryIDPUserColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPUserColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPUserColumn)) + return &MockIDPIntentRepositoryIDPUserColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPUserColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPUserColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPUserColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPUserColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPUserColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPUserColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPUserColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPUserColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPUserIDColumn mocks base method. +func (m *MockIDPIntentRepository) IDPUserIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPUserIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPUserIDColumn indicates an expected call of IDPUserIDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPUserIDColumn() *MockIDPIntentRepositoryIDPUserIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPUserIDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPUserIDColumn)) + return &MockIDPIntentRepositoryIDPUserIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPUserIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPUserIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPUserIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPUserIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPUserIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPUserIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPUserIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPUserIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPUserIDCondition mocks base method. +func (m *MockIDPIntentRepository) IDPUserIDCondition(idpUserID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPUserIDCondition", idpUserID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDPUserIDCondition indicates an expected call of IDPUserIDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPUserIDCondition(idpUserID any) *MockIDPIntentRepositoryIDPUserIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPUserIDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPUserIDCondition), idpUserID) + return &MockIDPIntentRepositoryIDPUserIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryIDPUserIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPUserIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPUserIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryIDPUserIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPUserIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryIDPUserIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPUserIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryIDPUserIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPUsernameColumn mocks base method. +func (m *MockIDPIntentRepository) IDPUsernameColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPUsernameColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// IDPUsernameColumn indicates an expected call of IDPUsernameColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPUsernameColumn() *MockIDPIntentRepositoryIDPUsernameColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPUsernameColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPUsernameColumn)) + return &MockIDPIntentRepositoryIDPUsernameColumnCall{Call: call} +} + +// MockIDPIntentRepositoryIDPUsernameColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPUsernameColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPUsernameColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryIDPUsernameColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPUsernameColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryIDPUsernameColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPUsernameColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryIDPUsernameColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// IDPUsernameCondition mocks base method. +func (m *MockIDPIntentRepository) IDPUsernameCondition(idpUsername string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IDPUsernameCondition", idpUsername) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// IDPUsernameCondition indicates an expected call of IDPUsernameCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) IDPUsernameCondition(idpUsername any) *MockIDPIntentRepositoryIDPUsernameConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IDPUsernameCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).IDPUsernameCondition), idpUsername) + return &MockIDPIntentRepositoryIDPUsernameConditionCall{Call: call} +} + +// MockIDPIntentRepositoryIDPUsernameConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryIDPUsernameConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryIDPUsernameConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryIDPUsernameConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryIDPUsernameConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryIDPUsernameConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryIDPUsernameConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryIDPUsernameConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDColumn mocks base method. +func (m *MockIDPIntentRepository) InstanceIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// InstanceIDColumn indicates an expected call of InstanceIDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) InstanceIDColumn() *MockIDPIntentRepositoryInstanceIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).InstanceIDColumn)) + return &MockIDPIntentRepositoryInstanceIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryInstanceIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryInstanceIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryInstanceIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryInstanceIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryInstanceIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryInstanceIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryInstanceIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryInstanceIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// InstanceIDCondition mocks base method. +func (m *MockIDPIntentRepository) InstanceIDCondition(instanceID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstanceIDCondition", instanceID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// InstanceIDCondition indicates an expected call of InstanceIDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) InstanceIDCondition(instanceID any) *MockIDPIntentRepositoryInstanceIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).InstanceIDCondition), instanceID) + return &MockIDPIntentRepositoryInstanceIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryInstanceIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryInstanceIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryInstanceIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryInstanceIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryInstanceIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryInstanceIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryInstanceIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryInstanceIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PrimaryKeyColumns mocks base method. +func (m *MockIDPIntentRepository) PrimaryKeyColumns() []database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrimaryKeyColumns") + ret0, _ := ret[0].([]database.Column) + return ret0 +} + +// PrimaryKeyColumns indicates an expected call of PrimaryKeyColumns. +func (mr *MockIDPIntentRepositoryMockRecorder) PrimaryKeyColumns() *MockIDPIntentRepositoryPrimaryKeyColumnsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyColumns", reflect.TypeOf((*MockIDPIntentRepository)(nil).PrimaryKeyColumns)) + return &MockIDPIntentRepositoryPrimaryKeyColumnsCall{Call: call} +} + +// MockIDPIntentRepositoryPrimaryKeyColumnsCall wrap *gomock.Call +type MockIDPIntentRepositoryPrimaryKeyColumnsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryPrimaryKeyColumnsCall) Return(arg0 []database.Column) *MockIDPIntentRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryPrimaryKeyColumnsCall) Do(f func() []database.Column) *MockIDPIntentRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryPrimaryKeyColumnsCall) DoAndReturn(f func() []database.Column) *MockIDPIntentRepositoryPrimaryKeyColumnsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// PrimaryKeyCondition mocks base method. +func (m *MockIDPIntentRepository) PrimaryKeyCondition(instanceID, id string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PrimaryKeyCondition", instanceID, id) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// PrimaryKeyCondition indicates an expected call of PrimaryKeyCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) PrimaryKeyCondition(instanceID, id any) *MockIDPIntentRepositoryPrimaryKeyConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PrimaryKeyCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).PrimaryKeyCondition), instanceID, id) + return &MockIDPIntentRepositoryPrimaryKeyConditionCall{Call: call} +} + +// MockIDPIntentRepositoryPrimaryKeyConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryPrimaryKeyConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryPrimaryKeyConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryPrimaryKeyConditionCall) Do(f func(string, string) database.Condition) *MockIDPIntentRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryPrimaryKeyConditionCall) DoAndReturn(f func(string, string) database.Condition) *MockIDPIntentRepositoryPrimaryKeyConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// RequestIDColumn mocks base method. +func (m *MockIDPIntentRepository) RequestIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// RequestIDColumn indicates an expected call of RequestIDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) RequestIDColumn() *MockIDPIntentRepositoryRequestIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestIDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).RequestIDColumn)) + return &MockIDPIntentRepositoryRequestIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryRequestIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryRequestIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryRequestIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryRequestIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryRequestIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryRequestIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryRequestIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryRequestIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// RequestIDCondition mocks base method. +func (m *MockIDPIntentRepository) RequestIDCondition(requestID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestIDCondition", requestID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// RequestIDCondition indicates an expected call of RequestIDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) RequestIDCondition(requestID any) *MockIDPIntentRepositoryRequestIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestIDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).RequestIDCondition), requestID) + return &MockIDPIntentRepositoryRequestIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryRequestIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryRequestIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryRequestIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryRequestIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryRequestIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryRequestIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryRequestIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryRequestIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetAssertion mocks base method. +func (m *MockIDPIntentRepository) SetAssertion(assertion []byte) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetAssertion", assertion) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetAssertion indicates an expected call of SetAssertion. +func (mr *MockIDPIntentRepositoryMockRecorder) SetAssertion(assertion any) *MockIDPIntentRepositorySetAssertionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAssertion", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetAssertion), assertion) + return &MockIDPIntentRepositorySetAssertionCall{Call: call} +} + +// MockIDPIntentRepositorySetAssertionCall wrap *gomock.Call +type MockIDPIntentRepositorySetAssertionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetAssertionCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetAssertionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetAssertionCall) Do(f func([]byte) database.Change) *MockIDPIntentRepositorySetAssertionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetAssertionCall) DoAndReturn(f func([]byte) database.Change) *MockIDPIntentRepositorySetAssertionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetExpiresAt mocks base method. +func (m *MockIDPIntentRepository) SetExpiresAt(expiration time.Time) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetExpiresAt", expiration) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetExpiresAt indicates an expected call of SetExpiresAt. +func (mr *MockIDPIntentRepositoryMockRecorder) SetExpiresAt(expiration any) *MockIDPIntentRepositorySetExpiresAtCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetExpiresAt", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetExpiresAt), expiration) + return &MockIDPIntentRepositorySetExpiresAtCall{Call: call} +} + +// MockIDPIntentRepositorySetExpiresAtCall wrap *gomock.Call +type MockIDPIntentRepositorySetExpiresAtCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetExpiresAtCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetExpiresAtCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetExpiresAtCall) Do(f func(time.Time) database.Change) *MockIDPIntentRepositorySetExpiresAtCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetExpiresAtCall) DoAndReturn(f func(time.Time) database.Change) *MockIDPIntentRepositorySetExpiresAtCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetFailReason mocks base method. +func (m *MockIDPIntentRepository) SetFailReason(reason string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetFailReason", reason) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetFailReason indicates an expected call of SetFailReason. +func (mr *MockIDPIntentRepositoryMockRecorder) SetFailReason(reason any) *MockIDPIntentRepositorySetFailReasonCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFailReason", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetFailReason), reason) + return &MockIDPIntentRepositorySetFailReasonCall{Call: call} +} + +// MockIDPIntentRepositorySetFailReasonCall wrap *gomock.Call +type MockIDPIntentRepositorySetFailReasonCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetFailReasonCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetFailReasonCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetFailReasonCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetFailReasonCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetFailReasonCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetFailReasonCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetFailedAt mocks base method. +func (m *MockIDPIntentRepository) SetFailedAt(failedAt time.Time) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetFailedAt", failedAt) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetFailedAt indicates an expected call of SetFailedAt. +func (mr *MockIDPIntentRepositoryMockRecorder) SetFailedAt(failedAt any) *MockIDPIntentRepositorySetFailedAtCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFailedAt", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetFailedAt), failedAt) + return &MockIDPIntentRepositorySetFailedAtCall{Call: call} +} + +// MockIDPIntentRepositorySetFailedAtCall wrap *gomock.Call +type MockIDPIntentRepositorySetFailedAtCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetFailedAtCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetFailedAtCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetFailedAtCall) Do(f func(time.Time) database.Change) *MockIDPIntentRepositorySetFailedAtCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetFailedAtCall) DoAndReturn(f func(time.Time) database.Change) *MockIDPIntentRepositorySetFailedAtCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetFailureURL mocks base method. +func (m *MockIDPIntentRepository) SetFailureURL(failureURL url.URL) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetFailureURL", failureURL) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetFailureURL indicates an expected call of SetFailureURL. +func (mr *MockIDPIntentRepositoryMockRecorder) SetFailureURL(failureURL any) *MockIDPIntentRepositorySetFailureURLCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetFailureURL", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetFailureURL), failureURL) + return &MockIDPIntentRepositorySetFailureURLCall{Call: call} +} + +// MockIDPIntentRepositorySetFailureURLCall wrap *gomock.Call +type MockIDPIntentRepositorySetFailureURLCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetFailureURLCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetFailureURLCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetFailureURLCall) Do(f func(url.URL) database.Change) *MockIDPIntentRepositorySetFailureURLCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetFailureURLCall) DoAndReturn(f func(url.URL) database.Change) *MockIDPIntentRepositorySetFailureURLCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPAccessToken mocks base method. +func (m *MockIDPIntentRepository) SetIDPAccessToken(idpAccessToken []byte) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPAccessToken", idpAccessToken) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPAccessToken indicates an expected call of SetIDPAccessToken. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPAccessToken(idpAccessToken any) *MockIDPIntentRepositorySetIDPAccessTokenCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPAccessToken", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPAccessToken), idpAccessToken) + return &MockIDPIntentRepositorySetIDPAccessTokenCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPAccessTokenCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPAccessTokenCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPAccessTokenCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPAccessTokenCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPAccessTokenCall) Do(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPAccessTokenCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPAccessTokenCall) DoAndReturn(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPAccessTokenCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPArguments mocks base method. +func (m *MockIDPIntentRepository) SetIDPArguments(idpArguments []byte) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPArguments", idpArguments) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPArguments indicates an expected call of SetIDPArguments. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPArguments(idpArguments any) *MockIDPIntentRepositorySetIDPArgumentsCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPArguments", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPArguments), idpArguments) + return &MockIDPIntentRepositorySetIDPArgumentsCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPArgumentsCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPArgumentsCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPArgumentsCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPArgumentsCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPArgumentsCall) Do(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPArgumentsCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPArgumentsCall) DoAndReturn(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPArgumentsCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPEntryAttributes mocks base method. +func (m *MockIDPIntentRepository) SetIDPEntryAttributes(idpEntryAttributes []byte) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPEntryAttributes", idpEntryAttributes) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPEntryAttributes indicates an expected call of SetIDPEntryAttributes. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPEntryAttributes(idpEntryAttributes any) *MockIDPIntentRepositorySetIDPEntryAttributesCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPEntryAttributes", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPEntryAttributes), idpEntryAttributes) + return &MockIDPIntentRepositorySetIDPEntryAttributesCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPEntryAttributesCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPEntryAttributesCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPEntryAttributesCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPEntryAttributesCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPEntryAttributesCall) Do(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPEntryAttributesCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPEntryAttributesCall) DoAndReturn(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPEntryAttributesCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPID mocks base method. +func (m *MockIDPIntentRepository) SetIDPID(idpID string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPID", idpID) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPID indicates an expected call of SetIDPID. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPID(idpID any) *MockIDPIntentRepositorySetIDPIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPID", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPID), idpID) + return &MockIDPIntentRepositorySetIDPIDCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPIDCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPIDCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPIDCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPIDCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetIDPIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPIDCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetIDPIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPIDToken mocks base method. +func (m *MockIDPIntentRepository) SetIDPIDToken(idpIDToken string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPIDToken", idpIDToken) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPIDToken indicates an expected call of SetIDPIDToken. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPIDToken(idpIDToken any) *MockIDPIntentRepositorySetIDPIDTokenCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPIDToken", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPIDToken), idpIDToken) + return &MockIDPIntentRepositorySetIDPIDTokenCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPIDTokenCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPIDTokenCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPIDTokenCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPIDTokenCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPIDTokenCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetIDPIDTokenCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPIDTokenCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetIDPIDTokenCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPUser mocks base method. +func (m *MockIDPIntentRepository) SetIDPUser(idpUser []byte) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPUser", idpUser) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPUser indicates an expected call of SetIDPUser. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPUser(idpUser any) *MockIDPIntentRepositorySetIDPUserCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPUser", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPUser), idpUser) + return &MockIDPIntentRepositorySetIDPUserCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPUserCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPUserCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPUserCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPUserCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPUserCall) Do(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPUserCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPUserCall) DoAndReturn(f func([]byte) database.Change) *MockIDPIntentRepositorySetIDPUserCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPUserID mocks base method. +func (m *MockIDPIntentRepository) SetIDPUserID(idpUserID string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPUserID", idpUserID) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPUserID indicates an expected call of SetIDPUserID. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPUserID(idpUserID any) *MockIDPIntentRepositorySetIDPUserIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPUserID", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPUserID), idpUserID) + return &MockIDPIntentRepositorySetIDPUserIDCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPUserIDCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPUserIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPUserIDCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPUserIDCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPUserIDCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetIDPUserIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPUserIDCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetIDPUserIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetIDPUsername mocks base method. +func (m *MockIDPIntentRepository) SetIDPUsername(idpUsername string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetIDPUsername", idpUsername) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetIDPUsername indicates an expected call of SetIDPUsername. +func (mr *MockIDPIntentRepositoryMockRecorder) SetIDPUsername(idpUsername any) *MockIDPIntentRepositorySetIDPUsernameCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIDPUsername", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetIDPUsername), idpUsername) + return &MockIDPIntentRepositorySetIDPUsernameCall{Call: call} +} + +// MockIDPIntentRepositorySetIDPUsernameCall wrap *gomock.Call +type MockIDPIntentRepositorySetIDPUsernameCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetIDPUsernameCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetIDPUsernameCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetIDPUsernameCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetIDPUsernameCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetIDPUsernameCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetIDPUsernameCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetRequestID mocks base method. +func (m *MockIDPIntentRepository) SetRequestID(requestID string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetRequestID", requestID) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetRequestID indicates an expected call of SetRequestID. +func (mr *MockIDPIntentRepositoryMockRecorder) SetRequestID(requestID any) *MockIDPIntentRepositorySetRequestIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRequestID", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetRequestID), requestID) + return &MockIDPIntentRepositorySetRequestIDCall{Call: call} +} + +// MockIDPIntentRepositorySetRequestIDCall wrap *gomock.Call +type MockIDPIntentRepositorySetRequestIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetRequestIDCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetRequestIDCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetRequestIDCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetRequestIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetRequestIDCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetRequestIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetState mocks base method. +func (m *MockIDPIntentRepository) SetState(state domain.IDPIntentState) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetState", state) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetState indicates an expected call of SetState. +func (mr *MockIDPIntentRepositoryMockRecorder) SetState(state any) *MockIDPIntentRepositorySetStateCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetState", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetState), state) + return &MockIDPIntentRepositorySetStateCall{Call: call} +} + +// MockIDPIntentRepositorySetStateCall wrap *gomock.Call +type MockIDPIntentRepositorySetStateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetStateCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetStateCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetStateCall) Do(f func(domain.IDPIntentState) database.Change) *MockIDPIntentRepositorySetStateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetStateCall) DoAndReturn(f func(domain.IDPIntentState) database.Change) *MockIDPIntentRepositorySetStateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetSucceededAt mocks base method. +func (m *MockIDPIntentRepository) SetSucceededAt(succeededAt time.Time) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSucceededAt", succeededAt) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetSucceededAt indicates an expected call of SetSucceededAt. +func (mr *MockIDPIntentRepositoryMockRecorder) SetSucceededAt(succeededAt any) *MockIDPIntentRepositorySetSucceededAtCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSucceededAt", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetSucceededAt), succeededAt) + return &MockIDPIntentRepositorySetSucceededAtCall{Call: call} +} + +// MockIDPIntentRepositorySetSucceededAtCall wrap *gomock.Call +type MockIDPIntentRepositorySetSucceededAtCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetSucceededAtCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetSucceededAtCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetSucceededAtCall) Do(f func(time.Time) database.Change) *MockIDPIntentRepositorySetSucceededAtCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetSucceededAtCall) DoAndReturn(f func(time.Time) database.Change) *MockIDPIntentRepositorySetSucceededAtCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetSuccessURL mocks base method. +func (m *MockIDPIntentRepository) SetSuccessURL(successURL url.URL) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSuccessURL", successURL) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetSuccessURL indicates an expected call of SetSuccessURL. +func (mr *MockIDPIntentRepositoryMockRecorder) SetSuccessURL(successURL any) *MockIDPIntentRepositorySetSuccessURLCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSuccessURL", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetSuccessURL), successURL) + return &MockIDPIntentRepositorySetSuccessURLCall{Call: call} +} + +// MockIDPIntentRepositorySetSuccessURLCall wrap *gomock.Call +type MockIDPIntentRepositorySetSuccessURLCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetSuccessURLCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetSuccessURLCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetSuccessURLCall) Do(f func(url.URL) database.Change) *MockIDPIntentRepositorySetSuccessURLCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetSuccessURLCall) DoAndReturn(f func(url.URL) database.Change) *MockIDPIntentRepositorySetSuccessURLCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SetUserID mocks base method. +func (m *MockIDPIntentRepository) SetUserID(userID string) database.Change { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUserID", userID) + ret0, _ := ret[0].(database.Change) + return ret0 +} + +// SetUserID indicates an expected call of SetUserID. +func (mr *MockIDPIntentRepositoryMockRecorder) SetUserID(userID any) *MockIDPIntentRepositorySetUserIDCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserID", reflect.TypeOf((*MockIDPIntentRepository)(nil).SetUserID), userID) + return &MockIDPIntentRepositorySetUserIDCall{Call: call} +} + +// MockIDPIntentRepositorySetUserIDCall wrap *gomock.Call +type MockIDPIntentRepositorySetUserIDCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySetUserIDCall) Return(arg0 database.Change) *MockIDPIntentRepositorySetUserIDCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySetUserIDCall) Do(f func(string) database.Change) *MockIDPIntentRepositorySetUserIDCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySetUserIDCall) DoAndReturn(f func(string) database.Change) *MockIDPIntentRepositorySetUserIDCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateColumn mocks base method. +func (m *MockIDPIntentRepository) StateColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// StateColumn indicates an expected call of StateColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) StateColumn() *MockIDPIntentRepositoryStateColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).StateColumn)) + return &MockIDPIntentRepositoryStateColumnCall{Call: call} +} + +// MockIDPIntentRepositoryStateColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryStateColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryStateColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryStateColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryStateColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryStateColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryStateColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryStateColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// StateCondition mocks base method. +func (m *MockIDPIntentRepository) StateCondition(state domain.IDPIntentState) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "StateCondition", state) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// StateCondition indicates an expected call of StateCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) StateCondition(state any) *MockIDPIntentRepositoryStateConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StateCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).StateCondition), state) + return &MockIDPIntentRepositoryStateConditionCall{Call: call} +} + +// MockIDPIntentRepositoryStateConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryStateConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryStateConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryStateConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryStateConditionCall) Do(f func(domain.IDPIntentState) database.Condition) *MockIDPIntentRepositoryStateConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryStateConditionCall) DoAndReturn(f func(domain.IDPIntentState) database.Condition) *MockIDPIntentRepositoryStateConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SucceededAtColumn mocks base method. +func (m *MockIDPIntentRepository) SucceededAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SucceededAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// SucceededAtColumn indicates an expected call of SucceededAtColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) SucceededAtColumn() *MockIDPIntentRepositorySucceededAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SucceededAtColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).SucceededAtColumn)) + return &MockIDPIntentRepositorySucceededAtColumnCall{Call: call} +} + +// MockIDPIntentRepositorySucceededAtColumnCall wrap *gomock.Call +type MockIDPIntentRepositorySucceededAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySucceededAtColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositorySucceededAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySucceededAtColumnCall) Do(f func() database.Column) *MockIDPIntentRepositorySucceededAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySucceededAtColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositorySucceededAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// SuccessURLColumn mocks base method. +func (m *MockIDPIntentRepository) SuccessURLColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SuccessURLColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// SuccessURLColumn indicates an expected call of SuccessURLColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) SuccessURLColumn() *MockIDPIntentRepositorySuccessURLColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuccessURLColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).SuccessURLColumn)) + return &MockIDPIntentRepositorySuccessURLColumnCall{Call: call} +} + +// MockIDPIntentRepositorySuccessURLColumnCall wrap *gomock.Call +type MockIDPIntentRepositorySuccessURLColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositorySuccessURLColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositorySuccessURLColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositorySuccessURLColumnCall) Do(f func() database.Column) *MockIDPIntentRepositorySuccessURLColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositorySuccessURLColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositorySuccessURLColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// Update mocks base method. +func (m *MockIDPIntentRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, client, condition} + for _, a := range changes { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "Update", varargs...) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update. +func (mr *MockIDPIntentRepositoryMockRecorder) Update(ctx, client, condition any, changes ...any) *MockIDPIntentRepositoryUpdateCall { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, client, condition}, changes...) + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockIDPIntentRepository)(nil).Update), varargs...) + return &MockIDPIntentRepositoryUpdateCall{Call: call} +} + +// MockIDPIntentRepositoryUpdateCall wrap *gomock.Call +type MockIDPIntentRepositoryUpdateCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryUpdateCall) Return(arg0 int64, arg1 error) *MockIDPIntentRepositoryUpdateCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryUpdateCall) Do(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockIDPIntentRepositoryUpdateCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryUpdateCall) DoAndReturn(f func(context.Context, database.QueryExecutor, database.Condition, ...database.Change) (int64, error)) *MockIDPIntentRepositoryUpdateCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdatedAtColumn mocks base method. +func (m *MockIDPIntentRepository) UpdatedAtColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatedAtColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UpdatedAtColumn indicates an expected call of UpdatedAtColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) UpdatedAtColumn() *MockIDPIntentRepositoryUpdatedAtColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).UpdatedAtColumn)) + return &MockIDPIntentRepositoryUpdatedAtColumnCall{Call: call} +} + +// MockIDPIntentRepositoryUpdatedAtColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryUpdatedAtColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryUpdatedAtColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryUpdatedAtColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryUpdatedAtColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryUpdatedAtColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryUpdatedAtColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UpdatedAtCondition mocks base method. +func (m *MockIDPIntentRepository) UpdatedAtCondition(op database.NumberOperation, updatedAt time.Time) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatedAtCondition", op, updatedAt) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// UpdatedAtCondition indicates an expected call of UpdatedAtCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) UpdatedAtCondition(op, updatedAt any) *MockIDPIntentRepositoryUpdatedAtConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatedAtCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).UpdatedAtCondition), op, updatedAt) + return &MockIDPIntentRepositoryUpdatedAtConditionCall{Call: call} +} + +// MockIDPIntentRepositoryUpdatedAtConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryUpdatedAtConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryUpdatedAtConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryUpdatedAtConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryUpdatedAtConditionCall) Do(f func(database.NumberOperation, time.Time) database.Condition) *MockIDPIntentRepositoryUpdatedAtConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryUpdatedAtConditionCall) DoAndReturn(f func(database.NumberOperation, time.Time) database.Condition) *MockIDPIntentRepositoryUpdatedAtConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UserIDColumn mocks base method. +func (m *MockIDPIntentRepository) UserIDColumn() database.Column { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UserIDColumn") + ret0, _ := ret[0].(database.Column) + return ret0 +} + +// UserIDColumn indicates an expected call of UserIDColumn. +func (mr *MockIDPIntentRepositoryMockRecorder) UserIDColumn() *MockIDPIntentRepositoryUserIDColumnCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDColumn", reflect.TypeOf((*MockIDPIntentRepository)(nil).UserIDColumn)) + return &MockIDPIntentRepositoryUserIDColumnCall{Call: call} +} + +// MockIDPIntentRepositoryUserIDColumnCall wrap *gomock.Call +type MockIDPIntentRepositoryUserIDColumnCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryUserIDColumnCall) Return(arg0 database.Column) *MockIDPIntentRepositoryUserIDColumnCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryUserIDColumnCall) Do(f func() database.Column) *MockIDPIntentRepositoryUserIDColumnCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryUserIDColumnCall) DoAndReturn(f func() database.Column) *MockIDPIntentRepositoryUserIDColumnCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + +// UserIDCondition mocks base method. +func (m *MockIDPIntentRepository) UserIDCondition(userID string) database.Condition { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UserIDCondition", userID) + ret0, _ := ret[0].(database.Condition) + return ret0 +} + +// UserIDCondition indicates an expected call of UserIDCondition. +func (mr *MockIDPIntentRepositoryMockRecorder) UserIDCondition(userID any) *MockIDPIntentRepositoryUserIDConditionCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserIDCondition", reflect.TypeOf((*MockIDPIntentRepository)(nil).UserIDCondition), userID) + return &MockIDPIntentRepositoryUserIDConditionCall{Call: call} +} + +// MockIDPIntentRepositoryUserIDConditionCall wrap *gomock.Call +type MockIDPIntentRepositoryUserIDConditionCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockIDPIntentRepositoryUserIDConditionCall) Return(arg0 database.Condition) *MockIDPIntentRepositoryUserIDConditionCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockIDPIntentRepositoryUserIDConditionCall) Do(f func(string) database.Condition) *MockIDPIntentRepositoryUserIDConditionCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockIDPIntentRepositoryUserIDConditionCall) DoAndReturn(f func(string) database.Condition) *MockIDPIntentRepositoryUserIDConditionCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table.go b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table.go new file mode 100644 index 000000000..3f3c8aa6c --- /dev/null +++ b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table.go @@ -0,0 +1,16 @@ +package migration + +import ( + _ "embed" +) + +var ( + //go:embed 012_identity_provider_intents_table/up.sql + up012IDPIntentsTable string + //go:embed 012_identity_provider_intents_table/down.sql + down012IDPIntentsTable string +) + +func init() { + registerSQLMigration(12, up012IDPIntentsTable, down012IDPIntentsTable) +} diff --git a/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/down.sql b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/down.sql new file mode 100644 index 000000000..28f7d3ec4 --- /dev/null +++ b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/down.sql @@ -0,0 +1,2 @@ +DROP TABLE IF EXISTS zitadel.identity_provider_intents; +DROP TYPE IF EXISTS zitadel.idp_intent_state; \ No newline at end of file diff --git a/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/up.sql b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/up.sql new file mode 100644 index 000000000..cfc23579d --- /dev/null +++ b/backend/v3/storage/database/dialect/postgres/migration/012_identity_provider_intents_table/up.sql @@ -0,0 +1,44 @@ +CREATE TYPE zitadel.idp_intent_state AS ENUM ( + 'started', + 'succeeded', + 'failed', + 'consumed' + ); + +CREATE TABLE zitadel.identity_provider_intents +( + instance_id TEXT NOT NULL, + id TEXT NOT NULL CHECK ( id <> '' ), + state zitadel.idp_intent_state NOT NULL DEFAULT 'started', + success_url TEXT, + failure_url TEXT, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + idp_id TEXT NOT NULL, + idp_arguments JSONB, + idp_user BYTEA, + idp_user_id TEXT, + idp_username TEXT, + user_id TEXT, + idp_access_token JSONB, + idp_id_token TEXT, + idp_entry_attributes JSONB, + request_id TEXT, + assertion JSONB, + succeeded_at TIMESTAMPTZ, + fail_reason TEXT, + failed_at TIMESTAMPTZ, + expires_at TIMESTAMPTZ, + + PRIMARY KEY (instance_id, id), + -- TODO(@adlerhurst): easiest would be to create the index in the user migrations so that we can merge this one but the problem is that the migration might fail if there are already intents created. + -- FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users (instance_id, id) ON DELETE CASCADE, + FOREIGN KEY (instance_id, idp_id) REFERENCES zitadel.identity_providers (instance_id, id) ON DELETE CASCADE +); + +CREATE TRIGGER trigger_set_updated_at + BEFORE UPDATE + ON zitadel.identity_provider_intents + FOR EACH ROW + WHEN (NEW.updated_at IS NULL) +EXECUTE FUNCTION zitadel.set_updated_at(); \ No newline at end of file diff --git a/backend/v3/storage/database/events_testing/events_test.go b/backend/v3/storage/database/events_testing/events_test.go index 3795ac113..07fc65fa4 100644 --- a/backend/v3/storage/database/events_testing/events_test.go +++ b/backend/v3/storage/database/events_testing/events_test.go @@ -69,7 +69,7 @@ func TestMain(m *testing.M) { CTX = integration.WithSystemAuthorization(ctx) Instance = integration.NewInstance(CTX) - IAMCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner) + IAMCTX = Instance.WithAuthorizationToken(ctx, integration.UserTypeIAMOwner) SystemClient = integration.SystemClient() OrgClient = Instance.Client.OrgV2beta ProjectClient = Instance.Client.Projectv2Beta 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 index a616a4502..6b3e2179f 100644 --- a/backend/v3/storage/database/events_testing/id_provider_instance_test.go +++ b/backend/v3/storage/database/events_testing/id_provider_instance_test.go @@ -145,17 +145,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) after := time.Now() require.NoError(t, err) @@ -190,17 +180,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { 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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) name = "new_" + name @@ -238,17 +218,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { 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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) // deactivate idp @@ -280,17 +250,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { 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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -342,17 +302,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -380,17 +330,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, false)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -427,17 +367,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -1968,40 +1898,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { // 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, - }, - }) + addLdap, err := AdminClient.AddLDAPProvider(IAMCTX, defaultInstanceLDAPRequest(name)) after := time.Now() require.NoError(t, err) @@ -2056,40 +1953,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }, - }) + addLdap, err := AdminClient.AddLDAPProvider(IAMCTX, defaultInstanceLDAPRequest(name)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -2328,25 +2192,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { // 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, - }) + addSAML, err := AdminClient.AddSAMLProvider(IAMCTX, defaultInstanceSAMLRequest(name, &federatedLogoutEnabled)) after := time.Now() require.NoError(t, err) @@ -2389,25 +2235,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { 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, - }) + addSAML, err := AdminClient.AddSAMLProvider(IAMCTX, defaultInstanceSAMLRequest(name, &federatedLogoutEnabled)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -2484,17 +2312,7 @@ func TestServer_TestIDProviderInstanceReduces(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, - }) + addOIDC, err := AdminClient.AddOIDCIDP(IAMCTX, defaultOIDCIDReq(name, true)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -2528,3 +2346,76 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) { }, retryDuration, tick) }) } + +func defaultInstanceSAMLRequest(name string, federatedLogoutEnable *bool) *admin.AddSAMLProviderRequest { + return &admin.AddSAMLProviderRequest{ + Name: name, + Metadata: &admin.AddSAMLProviderRequest_MetadataXml{ + MetadataXml: validSAMLMetadata1, + }, + Binding: idp.SAMLBinding_SAML_BINDING_POST, + WithSignedRequest: false, + TransientMappingAttributeName: &name, + FederatedLogoutEnabled: federatedLogoutEnable, + 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, + } +} + +func defaultOIDCIDReq(name string, autoRegister bool) *admin.AddOIDCIDPRequest { + return &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: autoRegister, + } +} + +func defaultInstanceLDAPRequest(name string) *admin.AddLDAPProviderRequest { + return &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, + }, + } +} 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 index 828856f55..22df986f8 100644 --- a/backend/v3/storage/database/events_testing/id_provider_org_test.go +++ b/backend/v3/storage/database/events_testing/id_provider_org_test.go @@ -1852,40 +1852,7 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) { // 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, - }, - }) + addLdap, err := MgmtClient.AddLDAPProvider(IAMCTX, defaultOrganizationLDAPRequest(name)) after := time.Now() require.NoError(t, err) @@ -1940,40 +1907,7 @@ func TestServer_TestIDProviderOrgReduces(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, - }, - }) + addLdap, err := MgmtClient.AddLDAPProvider(IAMCTX, defaultOrganizationLDAPRequest(name)) require.NoError(t, err) idpRepo := repository.IDProviderRepository() @@ -2412,3 +2346,40 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) { }, retryDuration, tick) }) } + +func defaultOrganizationLDAPRequest(providerName string) *management.AddLDAPProviderRequest { + return &management.AddLDAPProviderRequest{ + Name: providerName, + 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, + }, + } +} diff --git a/backend/v3/storage/database/events_testing/idp_intent_test.go b/backend/v3/storage/database/events_testing/idp_intent_test.go new file mode 100644 index 000000000..c9d99df16 --- /dev/null +++ b/backend/v3/storage/database/events_testing/idp_intent_test.go @@ -0,0 +1,396 @@ +//go:build integration + +package events_test + +// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced + +// import ( +// "net" +// "net/url" +// "testing" +// "time" + +// "github.com/brianvoe/gofakeit/v6" +// "github.com/muhlemmer/gu" +// "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" +// "github.com/zitadel/zitadel/internal/idp/providers/ldap" +// "github.com/zitadel/zitadel/internal/integration" +// "github.com/zitadel/zitadel/internal/integration/sink" +// "github.com/zitadel/zitadel/pkg/grpc/admin" +// "github.com/zitadel/zitadel/pkg/grpc/session/v2" +// "github.com/zitadel/zitadel/pkg/grpc/user/v2" +// ) + +// func TestServer_IDPIntentReduces(t *testing.T) { +// retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Minute) + +// idpIntentRepo := repository.IDPIntentRepository() +// instanceID := Instance.ID() + +// t.Run("start LDAP ID provider intent should create intent and succeed", func(t *testing.T) { +// ldapProvider, err := AdminClient.AddLDAPProvider(IAMCTX, defaultInstanceLDAPRequest(gofakeit.Name())) +// require.NoError(t, err) + +// req := &user.StartIdentityProviderIntentRequest{ +// IdpId: ldapProvider.GetId(), +// Content: &user.StartIdentityProviderIntentRequest_Ldap{ +// Ldap: &user.LDAPCredentials{ +// Username: "some-user", +// Password: "some-pass", +// }, +// }, +// } +// res, err := UserClient.StartIdentityProviderIntent(IAMCTX, req) +// require.NoError(t, err) +// idpIntent, ok := res.GetNextStep().(*user.StartIdentityProviderIntentResponse_IdpIntent) +// require.True(t, ok) +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntent.IdpIntent.GetIdpIntentId())) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: ldapProvider.GetId()}) +// }) +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(database.And( +// idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntent.IdpIntent.GetIdpIntentId()), +// idpIntentRepo.StateCondition(domain.IDPIntentStateSucceeded), +// )), +// ) +// require.NoError(collect, err) +// assert.Equal(collect, domain.IDPIntentStateSucceeded, retrievedRelationalIntent.State) +// assert.Empty(collect, retrievedRelationalIntent.SuccessURL) +// assert.Empty(collect, retrievedRelationalIntent.FailureURL) +// assert.Equal(collect, ldapProvider.GetId(), retrievedRelationalIntent.IDPID) +// assert.Nil(collect, retrievedRelationalIntent.IDPArguments) +// assert.NotEmpty(collect, retrievedRelationalIntent.IDPUser) +// assert.NotEmpty(collect, retrievedRelationalIntent.IDPUserID) +// assert.NotEmpty(collect, retrievedRelationalIntent.EntryAttributes) +// assert.True(collect, retrievedRelationalIntent.ExpiresAt.IsZero()) +// }, retryDuration, tick) +// }) + +// t.Run("oidc intent flow started with URLs should create intent in started state", func(t *testing.T) { +// idpCreateReq := defaultOIDCIDReq(gofakeit.Name(), true) +// idpCreateReq.Issuer = "http://localhost:8082" +// oidcIDP, err := AdminClient.AddOIDCIDP(IAMCTX, idpCreateReq) +// require.NoError(t, err) + +// req := &user.StartIdentityProviderIntentRequest{ +// IdpId: oidcIDP.GetIdpId(), +// Content: &user.StartIdentityProviderIntentRequest_Urls{ +// Urls: &user.RedirectURLs{ +// SuccessUrl: "https://localhost:8081/success", +// FailureUrl: "https://localhost:8081/fail", +// }, +// }, +// } +// res, err := UserClient.StartIdentityProviderIntent(IAMCTX, req) +// require.NoError(t, err) +// authURL, ok := res.GetNextStep().(*user.StartIdentityProviderIntentResponse_AuthUrl) +// require.True(t, ok) +// parsedAuthURL, err := url.Parse(authURL.AuthUrl) +// require.NoError(t, err) +// idpIntentID := parsedAuthURL.Query().Get("state") +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: oidcIDP.GetIdpId()}) +// }) +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)), +// ) +// require.NoError(collect, err) +// assert.Equal(collect, domain.IDPIntentStateStarted, retrievedRelationalIntent.State) +// assert.Equal(collect, "https://localhost:8081/success", retrievedRelationalIntent.SuccessURL.String()) +// assert.Equal(collect, "https://localhost:8081/fail", retrievedRelationalIntent.FailureURL.String()) +// assert.Empty(collect, retrievedRelationalIntent.IDPArguments) +// }, retryDuration, tick) + +// }) + +// t.Run("when successful oidc intent should update intent state to succeeded", func(t *testing.T) { +// beforeCreate := time.Now() +// idpCreateReq := defaultOIDCIDReq(gofakeit.Name(), true) +// idpCreateReq.Issuer = "http://localhost:8082" +// oidcIDP, err := AdminClient.AddOIDCIDP(IAMCTX, idpCreateReq) +// require.NoError(t, err) + +// expiryDate := time.Now().Add(time.Minute * 30) +// idpIntentID, _, _, _, err := sink.SuccessfulOIDCIntent(instanceID, oidcIDP.GetIdpId(), "some-idp-user", "some-user", expiryDate) +// require.NoError(t, err) +// afterSuccess := time.Now() +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: oidcIDP.GetIdpId()}) +// }) +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)), +// ) +// require.NoError(collect, err) +// assert.Equal(collect, domain.IDPIntentStateSucceeded, retrievedRelationalIntent.State) +// assert.NotEmpty(collect, retrievedRelationalIntent.IDPUser) +// assert.Equal(collect, "some-idp-user", retrievedRelationalIntent.IDPUserID) +// assert.Equal(collect, "username", retrievedRelationalIntent.IDPUsername) +// assert.Equal(collect, "some-user", retrievedRelationalIntent.UserID) +// assert.NotEmpty(collect, retrievedRelationalIntent.IDPAccessToken) +// assert.Equal(collect, "idToken", retrievedRelationalIntent.IDPIDToken) +// require.NotNil(collect, retrievedRelationalIntent.SucceededAt) +// assert.WithinRange(collect, *retrievedRelationalIntent.SucceededAt, beforeCreate, afterSuccess) +// require.NotNil(collect, retrievedRelationalIntent.ExpiresAt) +// assert.WithinRange(collect, *retrievedRelationalIntent.ExpiresAt, expiryDate.Add(time.Millisecond*-5), expiryDate.Add(time.Second*1)) +// }, retryDuration, tick) + +// }) + +// t.Run("when successful SAML intent should update intent state to succeeded", func(t *testing.T) { +// beforeCreate := time.Now() +// samlIDP, err := AdminClient.AddSAMLProvider(IAMCTX, defaultInstanceSAMLRequest(gofakeit.Name(), gu.Ptr(true))) +// require.NoError(t, err) + +// expiryDate := time.Now().Add(time.Minute * 30) +// idpIntentID, _, _, _, err := sink.SuccessfulSAMLIntent(instanceID, samlIDP.GetId(), "some-idp-user", "some-user", "", expiryDate) +// require.NoError(t, err) +// afterSuccess := time.Now() +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: samlIDP.GetId()}) +// }) +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)), +// ) +// require.NoError(collect, err) +// assert.Equal(collect, domain.IDPIntentStateSucceeded, retrievedRelationalIntent.State) +// assert.NotEmpty(collect, retrievedRelationalIntent.IDPUser) +// assert.Equal(collect, "some-idp-user", retrievedRelationalIntent.IDPUserID) +// assert.Empty(collect, retrievedRelationalIntent.IDPUsername) +// assert.Equal(collect, "some-user", retrievedRelationalIntent.UserID) +// assert.NotEmpty(collect, retrievedRelationalIntent.Assertion) +// require.NotNil(collect, retrievedRelationalIntent.SucceededAt) +// assert.WithinRange(collect, *retrievedRelationalIntent.SucceededAt, beforeCreate, afterSuccess) +// require.NotNil(collect, retrievedRelationalIntent.ExpiresAt) +// assert.WithinRange(collect, *retrievedRelationalIntent.ExpiresAt, expiryDate.Add(time.Millisecond*-5), expiryDate.Add(time.Second*1)) + +// }, retryDuration, tick) +// }) + +// t.Run("when emitting SAMLRequest event should update intent with request ID", func(t *testing.T) { +// samlIDP, err := AdminClient.AddSAMLProvider(IAMCTX, defaultInstanceSAMLRequest(gofakeit.Name(), gu.Ptr(true))) +// require.NoError(t, err) + +// expiry := time.Now().Add(time.Hour * 1) +// req := &user.StartIdentityProviderIntentRequest{ +// IdpId: samlIDP.GetId(), +// Content: &user.StartIdentityProviderIntentRequest_Urls{ +// Urls: &user.RedirectURLs{ +// SuccessUrl: "https://localhost:8081/success", +// FailureUrl: "https://localhost:8081/fail", +// }, +// }, +// } +// res, err := UserClient.StartIdentityProviderIntent(IAMCTX, req) +// require.NoError(t, err) +// formData, ok := res.GetNextStep().(*user.StartIdentityProviderIntentResponse_FormData) +// require.True(t, ok) + +// idpIntentID, ok := formData.FormData.GetFields()["RelayState"] +// require.True(t, ok) + +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: samlIDP.GetId()}) +// }) + +// idpIntentID, token, _, _, err := sink.SuccessfulSAMLIntent(instanceID, samlIDP.GetId(), "idp-user-id", "some-user", idpIntentID, expiry) +// require.NoError(t, err) + +// _, err = UserClient.RetrieveIdentityProviderIntent(IAMCTX, &user.RetrieveIdentityProviderIntentRequest{ +// IdpIntentId: idpIntentID, +// IdpIntentToken: token, +// }) +// require.NoError(t, err) +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(database.And( +// idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID), +// )), +// ) +// require.NoError(collect, err) +// assert.NotEmpty(collect, retrievedRelationalIntent.RequestID) +// }, retryDuration, tick) + +// }) + +// t.Run("when LDAP intent flow fails should update intent state and reason", func(t *testing.T) { +// beforeCreate := time.Now() +// ldapProvider, err := AdminClient.AddLDAPProvider(IAMCTX, defaultInstanceLDAPRequest(gofakeit.Name())) +// require.NoError(t, err) + +// req := &user.StartIdentityProviderIntentRequest{ +// IdpId: ldapProvider.GetId(), +// Content: &user.StartIdentityProviderIntentRequest_Ldap{ +// Ldap: &user.LDAPCredentials{ +// Username: ldap.FailingUser, +// Password: ldap.FailingPsw, +// }, +// }, +// } +// _, err = UserClient.StartIdentityProviderIntent(IAMCTX, req) +// require.Error(t, err) +// afterFail := time.Now() + +// var idpIntentID string +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, idpIntentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: ldapProvider.GetId()}) +// }) + +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// retrievedRelationalIntent, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(database.And( +// idpIntentRepo.InstanceIDCondition(instanceID), +// idpIntentRepo.StateCondition(domain.IDPIntentStateFailed), +// )), +// database.WithOrderByDescending(idpIntentRepo.CreatedAtColumn()), +// ) +// require.NoError(collect, err) +// assert.Equal(collect, domain.IDPIntentStateFailed, retrievedRelationalIntent.State) +// assert.NotEmpty(collect, retrievedRelationalIntent.FailReason) +// require.NotNil(collect, retrievedRelationalIntent.FailedAt) +// assert.WithinRange(collect, *retrievedRelationalIntent.FailedAt, beforeCreate, afterFail) +// idpIntentID = retrievedRelationalIntent.ID +// }, retryDuration, tick) +// }) + +// t.Run("when session update checks intent should delete intent", func(t *testing.T) { +// // ========== +// // GIVEN +// // ========== + +// // Create a user +// email := integration.Email() +// testUser := Instance.CreateUserTypeHuman(IAMCTX, email) +// _, err := UserClient.VerifyEmail(IAMCTX, &user.VerifyEmailRequest{ +// UserId: testUser.GetId(), +// VerificationCode: testUser.GetEmailCode(), +// }) +// require.NoError(t, err) +// _, err = UserClient.SetPassword(CTX, &user.SetPasswordRequest{ +// UserId: testUser.GetId(), +// NewPassword: &user.Password{ +// Password: integration.UserPassword, +// }, +// Verification: nil, +// }) +// require.NoError(t, err) + +// // Create an ID Provider +// idpID := Instance.AddGenericOAuthProvider(IAMCTX, integration.IDPName()).GetId() + +// // Link the user with the provider +// idpUserID := integration.ID() +// _, err = UserClient.AddIDPLink(IAMCTX, &user.AddIDPLinkRequest{ +// UserId: testUser.GetId(), +// IdpLink: &user.IDPLink{ +// IdpId: idpID, +// UserId: idpUserID, +// UserName: integration.Username(), +// }, +// }) +// require.NoError(t, err) + +// // Create an IDP intent +// _, err = url.Parse(Instance.CreateIntent(CTX, idpID).GetAuthUrl()) +// require.NoError(t, err) +// expiry := time.Now().Add(1 * time.Hour) + +// // Fake a successful intent flow +// intentID, intentToken, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, idpUserID, testUser.GetId(), expiry) +// require.NoError(t, err) + +// // Create a session for the user +// createdSessionID := createSessionForUser(t) +// require.NoError(t, err) + +// // ========== +// // TEST +// // ========== + +// // Update the session with user, password and IPDIntent checks +// _, err = SessionClient.SetSession(IAMCTX, &session.SetSessionRequest{ +// SessionId: createdSessionID, +// Checks: &session.Checks{ +// User: &session.CheckUser{ +// Search: &session.CheckUser_LoginName{ +// LoginName: email, +// }, +// }, +// Password: &session.CheckPassword{ +// Password: integration.UserPassword, +// }, +// IdpIntent: &session.CheckIDPIntent{ +// IdpIntentId: intentID, +// IdpIntentToken: intentToken, +// }, +// }, +// }) +// require.NoError(t, err) + +// // ========== +// // VERIFY +// // ========== +// t.Cleanup(func() { +// idpIntentRepo.Delete(IAMCTX, pool, idpIntentRepo.PrimaryKeyCondition(instanceID, intentID)) +// AdminClient.RemoveIDP(IAMCTX, &admin.RemoveIDPRequest{IdpId: idpID}) +// SessionClient.DeleteSession(IAMCTX, &session.DeleteSessionRequest{SessionId: createdSessionID}) +// }) + +// require.EventuallyWithT(t, func(collect *assert.CollectT) { +// _, err := idpIntentRepo.Get( +// IAMCTX, +// pool, +// database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, intentID)), +// ) +// assert.Error(collect, err) +// }, retryDuration, tick) +// }) +// } + +// func createSessionForUser(t *testing.T) (sessionID string) { +// t.Helper() +// lifetime := time.Hour +// createdSession, err := SessionClient.CreateSession(CTX, &session.CreateSessionRequest{ +// Checks: nil, +// Metadata: nil, +// Challenges: nil, +// UserAgent: &session.UserAgent{ +// FingerprintId: gu.Ptr(integration.ID()), +// Ip: gu.Ptr(net.IPv4(127, 0, 0, 1).String()), +// Description: gu.Ptr("description"), +// Header: map[string]*session.UserAgent_HeaderValues{ +// "User-Agent": {Values: []string{"ZITADEL-Integration-Test"}}, +// }, +// }, +// Lifetime: durationpb.New(lifetime), +// }) +// require.NoError(t, err) +// return createdSession.GetSessionId() +// } diff --git a/backend/v3/storage/database/repository/id_provider_test.go b/backend/v3/storage/database/repository/id_provider_test.go index 3f89b6cd2..68a11d8c0 100644 --- a/backend/v3/storage/database/repository/id_provider_test.go +++ b/backend/v3/storage/database/repository/id_provider_test.go @@ -28,19 +28,7 @@ func TestCreateIDProvider(t *testing.T) { }() // create instance - instanceId := gofakeit.Name() - instance := domain.Instance{ - ID: instanceId, - Name: gofakeit.Name(), - DefaultOrgID: "defaultOrgId", - IAMProjectID: "iamProject", - ConsoleClientID: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - instanceRepo := repository.InstanceRepository() - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + instanceId := createInstance(t, tx) // create org orgId := gofakeit.Name() @@ -61,7 +49,6 @@ func TestCreateIDProvider(t *testing.T) { err error } - // TESTS tests := []test{ { name: "happy path", @@ -83,11 +70,10 @@ func TestCreateIDProvider(t *testing.T) { { name: "create idp without name", idp: domain.IdentityProvider{ - InstanceID: instanceId, - OrgID: &orgId, - ID: gofakeit.Name(), - State: domain.IDPStateActive, - // Name: gofakeit.Name(), + InstanceID: instanceId, + OrgID: &orgId, + ID: gofakeit.Name(), + State: domain.IDPStateActive, Type: gu.Ptr(domain.IDPTypeOIDC), AllowCreation: true, AllowAutoCreation: true, @@ -231,9 +217,8 @@ func TestCreateIDProvider(t *testing.T) { { name: "adding idp with no id", idp: domain.IdentityProvider{ - InstanceID: instanceId, - OrgID: &orgId, - // ID: gofakeit.Name(), + InstanceID: instanceId, + OrgID: &orgId, State: domain.IDPStateActive, Name: gofakeit.Name(), Type: gu.Ptr(domain.IDPTypeOIDC), @@ -249,11 +234,10 @@ func TestCreateIDProvider(t *testing.T) { { name: "adding idp with no name", idp: domain.IdentityProvider{ - InstanceID: instanceId, - OrgID: &orgId, - ID: gofakeit.Name(), - State: domain.IDPStateActive, - // Name: gofakeit.Name(), + InstanceID: instanceId, + OrgID: &orgId, + ID: gofakeit.Name(), + State: domain.IDPStateActive, Type: gu.Ptr(domain.IDPTypeOIDC), AllowCreation: true, AllowAutoCreation: true, @@ -267,7 +251,6 @@ func TestCreateIDProvider(t *testing.T) { { name: "adding idp with no instance id", idp: domain.IdentityProvider{ - // InstanceID: instanceId, OrgID: &orgId, State: domain.IDPStateActive, Name: gofakeit.Name(), @@ -384,31 +367,10 @@ func TestUpdateIDProvider(t *testing.T) { }() // create instance - instanceId := gofakeit.Name() - instance := domain.Instance{ - ID: instanceId, - Name: gofakeit.Name(), - DefaultOrgID: "defaultOrgId", - IAMProjectID: "iamProject", - ConsoleClientID: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - instanceRepo := repository.InstanceRepository() - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + instanceId := createInstance(t, tx) // 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) + orgId := createOrganization(t, tx, instanceId) idpRepo := repository.IDProviderRepository() @@ -669,44 +631,12 @@ func TestGetIDProvider(t *testing.T) { } }() - // create instance - instanceId := gofakeit.Name() - instance := domain.Instance{ - ID: instanceId, - Name: gofakeit.Name(), - DefaultOrgID: "defaultOrgId", - IAMProjectID: "iamProject", - ConsoleClientID: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - instanceRepo := repository.InstanceRepository() - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + instanceId := createInstance(t, tx) + orgId := createOrganization(t, tx, instanceId) - // 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) + createOrganization(t, tx, instanceId) idpRepo := repository.IDProviderRepository() type test struct { @@ -955,31 +885,10 @@ func TestListIDProvider(t *testing.T) { }() // create instance - instanceId := gofakeit.Name() - instance := domain.Instance{ - ID: instanceId, - Name: gofakeit.Name(), - DefaultOrgID: "defaultOrgId", - IAMProjectID: "iamProject", - ConsoleClientID: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - instanceRepo := repository.InstanceRepository() - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + instanceId := createInstance(t, tx) // 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) + orgId := createOrganization(t, tx, instanceId) idpRepo := repository.IDProviderRepository() @@ -994,30 +903,10 @@ func TestListIDProvider(t *testing.T) { 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: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + newInstanceId := createInstance(t, tx) // 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) + newOrgId := createOrganization(t, tx, newInstanceId) // create idp // this idp is created as an additional idp which should NOT @@ -1785,31 +1674,10 @@ func TestDeleteIDProvider(t *testing.T) { }() // create instance - instanceId := gofakeit.Name() - instance := domain.Instance{ - ID: instanceId, - Name: gofakeit.Name(), - DefaultOrgID: "defaultOrgId", - IAMProjectID: "iamProject", - ConsoleClientID: "managementConsoleCLient", - ConsoleAppID: "managementConsoleApp", - DefaultLanguage: "defaultLanguage", - } - instanceRepo := repository.InstanceRepository() - err = instanceRepo.Create(t.Context(), tx, &instance) - require.NoError(t, err) + instanceId := createInstance(t, tx) // 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) + orgId := createOrganization(t, tx, instanceId) idpRepo := repository.IDProviderRepository() diff --git a/backend/v3/storage/database/repository/idp_intent.go b/backend/v3/storage/database/repository/idp_intent.go new file mode 100644 index 000000000..9e617bfa6 --- /dev/null +++ b/backend/v3/storage/database/repository/idp_intent.go @@ -0,0 +1,442 @@ +package repository + +import ( + "context" + "fmt" + "net/url" + "time" + + "github.com/muhlemmer/gu" + + "github.com/zitadel/zitadel/backend/v3/domain" + "github.com/zitadel/zitadel/backend/v3/storage/database" +) + +type idpIntentRepository struct{} + +func (i idpIntentRepository) qualifiedTableName() string { + return "zitadel.identity_provider_intents" +} + +func (i idpIntentRepository) unqualifiedTableName() string { + return "identity_provider_intents" +} + +func IDPIntentRepository() domain.IDPIntentRepository { + return new(idpIntentRepository) +} + +// ------------------------------------------------------------- +// repository +// ------------------------------------------------------------- + +const queryIDPIntentStmt = ` +SELECT + identity_provider_intents.instance_id + , identity_provider_intents.id + , identity_provider_intents.state + , identity_provider_intents.success_url + , identity_provider_intents.failure_url + , identity_provider_intents.created_at + , identity_provider_intents.updated_at + , identity_provider_intents.idp_id + , identity_provider_intents.idp_arguments + , identity_provider_intents.idp_user + , identity_provider_intents.idp_user_id + , identity_provider_intents.idp_username + , identity_provider_intents.user_id + , identity_provider_intents.idp_access_token + , identity_provider_intents.idp_id_token + , identity_provider_intents.idp_entry_attributes + , identity_provider_intents.request_id + , identity_provider_intents.assertion + , identity_provider_intents.succeeded_at + , identity_provider_intents.failed_at + , identity_provider_intents.fail_reason + , identity_provider_intents.expires_at +FROM + zitadel.identity_provider_intents +` + +// Create implements [domain.IDPIntentRepository]. +func (i idpIntentRepository) Create(ctx context.Context, client database.QueryExecutor, intent *domain.IDPIntent) error { + var createdAt any = database.DefaultInstruction + if !intent.CreatedAt.IsZero() { + createdAt = intent.CreatedAt + } + var updatedAt = createdAt + if !intent.UpdatedAt.IsZero() { + updatedAt = intent.UpdatedAt + } + + builder := new(database.StatementBuilder) + builder.WriteString(`INSERT INTO ` + i.qualifiedTableName() + ` (instance_id, id, success_url, failure_url, idp_id, idp_arguments, created_at, updated_at) VALUES ( `) + builder.WriteArgs(intent.InstanceID, intent.ID, intent.SuccessURL.String(), intent.FailureURL.String(), intent.IDPID, intent.IDPArguments, createdAt, updatedAt) + builder.WriteString(` ) RETURNING created_at, updated_at`) + return client.QueryRow(ctx, builder.String(), builder.Args()...).Scan(&intent.CreatedAt, &intent.UpdatedAt) +} + +// Delete implements [domain.IDPIntentRepository]. +func (i idpIntentRepository) Delete(ctx context.Context, client database.QueryExecutor, condition database.Condition) (int64, error) { + return deleteOne(ctx, client, i, condition) +} + +// Get implements [domain.IDPIntentRepository]. +func (i idpIntentRepository) Get(ctx context.Context, client database.QueryExecutor, opts ...database.QueryOption) (*domain.IDPIntent, error) { + options := new(database.QueryOpts) + for _, opt := range opts { + opt(options) + } + + if options.Condition == nil || !options.Condition.IsRestrictingColumn(i.InstanceIDColumn()) { + return nil, database.NewMissingConditionError(i.InstanceIDColumn()) + } + + var builder database.StatementBuilder + builder.WriteString(queryIDPIntentStmt) + options.Write(&builder) + fmt.Println(builder.String()) + + return scanIDPIntent(ctx, client, &builder) +} + +type rawIDPIntent struct { + *domain.IDPIntent + SuccessURL string `json:"success_url,omitempty" db:"success_url"` + FailureURL string `json:"failure_url,omitempty" db:"failure_url"` + IDPUserID *string `json:"idp_user_id,omitempty" db:"idp_user_id"` + IDPUsername *string `json:"idp_username,omitempty" db:"idp_username"` + UserID *string `json:"user_id,omitempty" db:"user_id"` + IDPIDToken *string `json:"idp_id_token,omitempty" db:"idp_id_token"` + RequestID *string `json:"request_id,omitempty" db:"request_id"` + FailReason *string `json:"fail_reason,omitempty" db:"fail_reason"` +} + +func scanIDPIntent(ctx context.Context, querier database.QueryExecutor, builder *database.StatementBuilder) (*domain.IDPIntent, error) { + rows, err := querier.Query(ctx, builder.String(), builder.Args()...) + if err != nil { + return nil, err + } + + raw := new(rawIDPIntent) + if err := rows.(database.CollectableRows).CollectExactlyOneRow(raw); err != nil { + return nil, err + } + return rawIDPIntentToDomain(raw) +} + +func rawIDPIntentToDomain(raw *rawIDPIntent) (*domain.IDPIntent, error) { + successURL, _ := url.Parse(raw.SuccessURL) + failureURL, _ := url.Parse(raw.FailureURL) + raw.IDPIntent.SuccessURL = successURL + raw.IDPIntent.FailureURL = failureURL + raw.IDPIntent.IDPUserID = gu.Value(raw.IDPUserID) + raw.IDPIntent.IDPUsername = gu.Value(raw.IDPUsername) + raw.IDPIntent.UserID = gu.Value(raw.UserID) + raw.IDPIntent.IDPIDToken = gu.Value(raw.IDPIDToken) + raw.IDPIntent.RequestID = gu.Value(raw.RequestID) + raw.IDPIntent.FailReason = gu.Value(raw.FailReason) + + return raw.IDPIntent, nil +} + +// Update implements [domain.IDPIntentRepository]. +func (i idpIntentRepository) Update(ctx context.Context, client database.QueryExecutor, condition database.Condition, changes ...database.Change) (int64, error) { + if changes == nil { + return 0, database.ErrNoChanges + } + if condition == nil || !condition.IsRestrictingColumn(i.InstanceIDColumn()) { + return 0, database.NewMissingConditionError(i.InstanceIDColumn()) + } + if !database.Changes(changes).IsOnColumn(i.UpdatedAtColumn()) { + changes = append(changes, database.NewChange(i.UpdatedAtColumn(), database.DefaultInstruction)) + } + + builder := database.StatementBuilder{} + builder.WriteString(`UPDATE zitadel.identity_provider_intents SET `) + + err := database.Changes(changes).Write(&builder) + if err != nil { + return 0, err + } + writeCondition(&builder, condition) + + return client.Exec(ctx, builder.String(), builder.Args()...) +} + +// ------------------------------------------------------------- +// changes +// ------------------------------------------------------------- + +// SetAssertion implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetAssertion(assertion []byte) database.Change { + return database.NewChange(i.AssertionColumn(), assertion) +} + +// SetFailureURL implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetFailureURL(failureURL url.URL) database.Change { + return database.NewChange(i.FailureURLColumn(), failureURL.String()) +} + +// SetIDPAccessToken implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPAccessToken(idpAccessToken []byte) database.Change { + return database.NewChange(i.IDPAccessTokenColumn(), idpAccessToken) +} + +// SetIDPIDToken implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) SetIDPIDToken(idpIDToken string) database.Change { + return database.NewChange(i.IDPIDTokenColumn(), idpIDToken) +} + +// SetIDPArguments implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPArguments(idpArguments []byte) database.Change { + return database.NewChange(i.IDPArgumentsColumn(), idpArguments) +} + +// SetIDPEntryAttributes implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPEntryAttributes(idpEntryAttributes []byte) database.Change { + return database.NewChange(i.IDPEntryAttributesColumn(), idpEntryAttributes) +} + +// SetIDPID implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPID(idpID string) database.Change { + return database.NewChange(i.IDPIDColumn(), idpID) +} + +// SetIDPUser implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPUser(idpUser []byte) database.Change { + return database.NewChange(i.IDPUserColumn(), idpUser) +} + +// SetIDPUserID implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPUserID(idpUserID string) database.Change { + return database.NewChange(i.IDPUserIDColumn(), idpUserID) +} + +// SetIDPUsername implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetIDPUsername(idpUsername string) database.Change { + return database.NewChange(i.IDPUsernameColumn(), idpUsername) +} + +// SetRequestID implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetRequestID(requestID string) database.Change { + return database.NewChange(i.RequestIDColumn(), requestID) +} + +// SetState implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetState(state domain.IDPIntentState) database.Change { + return database.NewChange(i.StateColumn(), state) +} + +// SetSuccessURL implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetSuccessURL(successURL url.URL) database.Change { + return database.NewChange(i.SuccessURLColumn(), successURL.String()) +} + +// SetUserID implements [domain.idpIntentChanges]. +func (i idpIntentRepository) SetUserID(userID string) database.Change { + return database.NewChange(i.UserIDColumn(), userID) +} + +// SetExpiresAt implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) SetExpiresAt(expiration time.Time) database.Change { + return database.NewChange(i.ExpiresAtColumn(), expiration) +} + +// SetSucceededAt implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) SetSucceededAt(succeededAt time.Time) database.Change { + return database.NewChange(i.SucceededAtColumn(), succeededAt) +} + +// SetFailedAt implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) SetFailedAt(failedAt time.Time) database.Change { + return database.NewChange(i.FailedAtColumn(), failedAt) +} + +// SetFailReason implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) SetFailReason(reason string) database.Change { + return database.NewChange(i.FailReasonColumn(), reason) +} + +// ------------------------------------------------------------- +// conditions +// ------------------------------------------------------------- + +// CreatedAtCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) CreatedAtCondition(op database.NumberOperation, createdAt time.Time) database.Condition { + return database.NewNumberCondition(i.CreatedAtColumn(), op, createdAt) +} + +// IDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) IDCondition(id string) database.Condition { + return database.NewTextCondition(i.IDColumn(), database.TextOperationEqual, id) +} + +// IDPIDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) IDPIDCondition(idpID string) database.Condition { + return database.NewTextCondition(i.IDPIDColumn(), database.TextOperationEqual, idpID) +} + +// IDPUserIDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) IDPUserIDCondition(idpUserID string) database.Condition { + return database.NewTextCondition(i.IDPUserIDColumn(), database.TextOperationEqual, idpUserID) +} + +// IDPUsernameCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) IDPUsernameCondition(idpUsername string) database.Condition { + return database.NewTextCondition(i.IDPUsernameColumn(), database.TextOperationEqual, idpUsername) +} + +// InstanceIDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) InstanceIDCondition(instanceID string) database.Condition { + return database.NewTextCondition(i.InstanceIDColumn(), database.TextOperationEqual, instanceID) +} + +// PrimaryKeyCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) PrimaryKeyCondition(instanceID, id string) database.Condition { + return database.And( + i.InstanceIDCondition(instanceID), + i.IDCondition(id), + ) +} + +// RequestIDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) RequestIDCondition(requestID string) database.Condition { + return database.NewTextCondition(i.RequestIDColumn(), database.TextOperationEqual, requestID) +} + +// StateCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) StateCondition(state domain.IDPIntentState) database.Condition { + return database.NewTextCondition(i.StateColumn(), database.TextOperationEqual, state.String()) +} + +// UpdatedAtCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) UpdatedAtCondition(op database.NumberOperation, updatedAt time.Time) database.Condition { + return database.NewNumberCondition(i.UpdatedAtColumn(), op, updatedAt) +} + +// UserIDCondition implements [domain.idpIntentConditions]. +func (i idpIntentRepository) UserIDCondition(userID string) database.Condition { + return database.NewTextCondition(i.UserIDColumn(), database.TextOperationEqual, userID) +} + +// ------------------------------------------------------------- +// columns +// ------------------------------------------------------------- + +// AssertionColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) AssertionColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "assertion") +} + +// CreatedAtColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) CreatedAtColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "created_at") +} + +// ExpiresAtColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) ExpiresAtColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "expires_at") +} + +// FailureURLColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) FailureURLColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "failure_url") +} + +// IDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "id") +} + +// IDPAccessTokenColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPAccessTokenColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_access_token") +} + +// IDPIDTokenColumn implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) IDPIDTokenColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_id_token") +} + +// IDPArgumentsColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPArgumentsColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_arguments") +} + +// IDPEntryAttributesColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPEntryAttributesColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_entry_attributes") +} + +// IDPIDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPIDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_id") +} + +// IDPUserColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPUserColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_user") +} + +// IDPUserIDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPUserIDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_user_id") +} + +// IDPUsernameColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) IDPUsernameColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "idp_username") +} + +// InstanceIDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) InstanceIDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "instance_id") +} + +// PrimaryKeyColumns implements [domain.IDPIntentRepository]. +func (i idpIntentRepository) PrimaryKeyColumns() []database.Column { + return []database.Column{i.IDColumn(), i.InstanceIDColumn()} +} + +// RequestIDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) RequestIDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "request_id") +} + +// StateColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) StateColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "state") +} + +// SucceededAtColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) SucceededAtColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "succeeded_at") +} + +// SuccessURLColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) SuccessURLColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "success_url") +} + +// FailReasonColumn implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) FailReasonColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "fail_reason") +} + +// FailedAtColumn implements [domain.IDPIntentRepository]. +func (i *idpIntentRepository) FailedAtColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "failed_at") +} + +// UpdatedAtColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) UpdatedAtColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "updated_at") +} + +// UserIDColumn implements [domain.idpIntentColumns]. +func (i idpIntentRepository) UserIDColumn() database.Column { + return database.NewColumn(i.unqualifiedTableName(), "user_id") +} + +var _ domain.IDPIntentRepository = (*idpIntentRepository)(nil) diff --git a/backend/v3/storage/database/repository/idp_intent_test.go b/backend/v3/storage/database/repository/idp_intent_test.go new file mode 100644 index 000000000..9227d8ecb --- /dev/null +++ b/backend/v3/storage/database/repository/idp_intent_test.go @@ -0,0 +1,591 @@ +package repository_test + +import ( + "encoding/json" + "net/url" + "testing" + "time" + + "github.com/brianvoe/gofakeit/v6" + "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" +) + +func TestCreateIDPIntent(t *testing.T) { + beforeCreate := time.Now() + tx, err := pool.Begin(t.Context(), nil) + require.NoError(t, err) + defer func() { + err := tx.Rollback(t.Context()) + require.NoError(t, err) + }() + + instanceID := createInstance(t, tx) + orgID := createOrganization(t, tx, instanceID) + idpID := createIdentityProvider(t, tx, instanceID, orgID) + + successURL, err := url.Parse("https://example.com/success") + require.NoError(t, err) + failURL, err := url.Parse("https://example.com/fail") + require.NoError(t, err) + + emptyURL, err := url.Parse("") + require.NoError(t, err) + + intentID := gofakeit.UUID() + tt := []struct { + testName string + + inputID string + inputInstanceID string + inputSuccessURL *url.URL + inputFailureURL *url.URL + inputIDPID string + inputIDPArgs map[string]any + inputCreatedAt time.Time + inputUpdatedAt time.Time + inputMaxLifetime time.Duration + + expectedError error + }{ + { + testName: "create and update timestamps not set / empty fail url / should generate timestamps and retrieve successfully", + inputID: intentID, + inputInstanceID: instanceID, + inputSuccessURL: successURL, + inputFailureURL: emptyURL, + inputIDPID: idpID, + inputIDPArgs: map[string]any{ + "arg1": map[string]any{"k1": 1, "k2": "v2"}, + "arg2": 2, + "arg3": "3", + "arg4": true, + }, + inputMaxLifetime: time.Hour * 2, + }, + { + testName: "all set / should retrieve successfully", + inputID: intentID, + inputInstanceID: instanceID, + inputSuccessURL: successURL, + inputFailureURL: failURL, + inputIDPID: idpID, + inputIDPArgs: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + inputMaxLifetime: time.Hour * 2, + inputCreatedAt: time.Now(), + inputUpdatedAt: time.Now(), + }, + { + testName: "id not set / should return check error", + inputCreatedAt: time.Now(), + inputUpdatedAt: time.Now(), + inputInstanceID: instanceID, + inputSuccessURL: successURL, + inputFailureURL: emptyURL, + inputIDPID: idpID, + inputIDPArgs: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + expectedError: database.NewCheckError("", "", nil), + }, + { + testName: "instance id not found / should return foreign key error", + inputID: intentID, + inputCreatedAt: time.Now(), + inputUpdatedAt: time.Now(), + inputSuccessURL: successURL, + inputFailureURL: emptyURL, + inputIDPID: idpID, + inputIDPArgs: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + expectedError: database.NewForeignKeyError("", "", nil), + }, + { + testName: "idp id not found / should return foreign key error", + inputID: intentID, + inputInstanceID: instanceID, + inputCreatedAt: time.Now(), + inputUpdatedAt: time.Now(), + inputSuccessURL: successURL, + inputFailureURL: failURL, + inputIDPArgs: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + expectedError: database.NewForeignKeyError("", "", nil), + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + // Given + savePoint, savePointErr := tx.Begin(t.Context()) + require.NoError(t, savePointErr) + defer func() { + err := savePoint.Rollback(t.Context()) + require.NoError(t, err) + }() + + idpIntentRepo := repository.IDPIntentRepository() + intent := domain.IDPIntent{ + ID: tc.inputID, + InstanceID: tc.inputInstanceID, + SuccessURL: tc.inputSuccessURL, + FailureURL: tc.inputFailureURL, + IDPID: tc.inputIDPID, + IDPArguments: tc.inputIDPArgs, + + State: domain.IDPIntentStateFailed, // Should disregard + IDPUserID: "should disregard", + } + + // Test + createErr := idpIntentRepo.Create(t.Context(), tx, &intent) + afterCreate := time.Now() + + // Verify + assert.ErrorIs(t, createErr, tc.expectedError) + if tc.expectedError == nil { + retrieved, getErr := idpIntentRepo.Get(t.Context(), tx, database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, intentID))) + require.NoError(t, getErr) + require.NotNil(t, retrieved) + + assert.WithinRange(t, retrieved.CreatedAt, beforeCreate, afterCreate) + assert.WithinRange(t, retrieved.UpdatedAt, beforeCreate, afterCreate) + assert.NotZero(t, retrieved.ID) + if tc.inputID != "" { + assert.Equal(t, tc.inputID, retrieved.ID) + } + assert.Equal(t, tc.inputInstanceID, retrieved.InstanceID) + assert.Equal(t, tc.inputSuccessURL, retrieved.SuccessURL) + assert.Equal(t, tc.inputFailureURL, retrieved.FailureURL) + assert.Equal(t, tc.inputIDPID, retrieved.IDPID) + assert.NotZero(t, retrieved.IDPArguments) + assert.Equal(t, domain.IDPIntentStateStarted, retrieved.State) + assert.Zero(t, retrieved.IDPUserID) + } + }) + } +} + +func TestGetIDPIntent(t *testing.T) { + tx, err := pool.Begin(t.Context(), nil) + require.NoError(t, err) + defer func() { + err := tx.Rollback(t.Context()) + require.NoError(t, err) + }() + + instanceID := createInstance(t, tx) + orgID := createOrganization(t, tx, instanceID) + idpID := createIdentityProvider(t, tx, instanceID, orgID) + + idpIntentRepo := repository.IDPIntentRepository() + + intentID1 := createIDPIntent(t, tx, instanceID, idpID) + successURL, err := url.Parse("https://example.com/success") + require.NoError(t, err) + failURL, err := url.Parse("https://example.com/fail") + require.NoError(t, err) + + intent2 := domain.IDPIntent{ + ID: gofakeit.UUID(), + InstanceID: instanceID, + SuccessURL: successURL, + FailureURL: failURL, + IDPID: idpID, + IDPArguments: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + CreatedAt: time.Now().AddDate(0, 0, 1), + } + err = idpIntentRepo.Create(t.Context(), tx, &intent2) + require.NoError(t, err) + + tt := []struct { + testName string + inputQueryOpts []database.QueryOption + expectedError error + expectedIntentID string + }{ + { + testName: "when no condition set should return missing condition error", + expectedError: database.NewMissingConditionError(nil), + }, + { + testName: "when no instance condition set should return missing condition error", + inputQueryOpts: []database.QueryOption{ + database.WithCondition(idpIntentRepo.IDCondition(intentID1)), + }, + expectedError: database.NewMissingConditionError(nil), + }, + { + testName: "when primary key condition set should return matching intent", + inputQueryOpts: []database.QueryOption{ + database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1)), + }, + expectedIntentID: intentID1, + }, + { + testName: "when filtering by creation date descending should return matching intent with highest PK", + inputQueryOpts: []database.QueryOption{ + database.WithCondition(database.And( + idpIntentRepo.InstanceIDCondition(instanceID), + )), + database.WithOrderByDescending(idpIntentRepo.CreatedAtColumn()), + database.WithLimit(1), + }, + expectedIntentID: intent2.ID, + }, + { + testName: "when filtering by non-existent PK should return no row found error", + inputQueryOpts: []database.QueryOption{ + database.WithCondition(database.And( + idpIntentRepo.InstanceIDCondition(instanceID), + idpIntentRepo.IDCondition("not existing"), + )), + }, + expectedError: database.NewNoRowFoundError(nil), + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + // Test + retrieved, err := idpIntentRepo.Get(t.Context(), tx, tc.inputQueryOpts...) + + // Verify + assert.ErrorIs(t, err, tc.expectedError) + if tc.expectedError == nil { + assert.Equal(t, tc.expectedIntentID, retrieved.ID) + assert.Equal(t, "https://example.com/success", retrieved.SuccessURL.String()) + assert.Equal(t, "https://example.com/fail", retrieved.FailureURL.String()) + } + }) + } +} + +func TestUpdateIDPIntent(t *testing.T) { + beforeUpdate := time.Now() + + tx, err := pool.Begin(t.Context(), nil) + require.NoError(t, err) + defer func() { + err := tx.Rollback(t.Context()) + require.NoError(t, err) + }() + + instanceID := createInstance(t, tx) + orgID := createOrganization(t, tx, instanceID) + idpID := createIdentityProvider(t, tx, instanceID, orgID) + + idpIntentRepo := repository.IDPIntentRepository() + + successURL, err := url.Parse("https://example.com/success") + require.NoError(t, err) + failURL, err := url.Parse("https://example.com/fail") + require.NoError(t, err) + + intentID1 := gofakeit.UUID() + intent1 := domain.IDPIntent{ + ID: intentID1, + InstanceID: instanceID, + SuccessURL: successURL, + FailureURL: failURL, + IDPID: idpID, + IDPArguments: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}, "arg2": []int32{1}}, + CreatedAt: time.Now(), + } + err = idpIntentRepo.Create(t.Context(), tx, &intent1) + require.NoError(t, err) + + entryAttrs := map[string][]string{ + "attr1": {"1", "2"}, + "attr2": {"3", "4"}, + } + marshalledAttrs, marshallErr := json.Marshal(entryAttrs) + require.NoError(t, marshallErr) + + intentID2 := gofakeit.UUID() + intent2 := domain.IDPIntent{ + ID: intentID2, + InstanceID: instanceID, + SuccessURL: successURL, + FailureURL: failURL, + IDPID: idpID, + IDPArguments: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + CreatedAt: time.Now(), + } + err = idpIntentRepo.Create(t.Context(), tx, &intent2) + require.NoError(t, err) + + now := time.Now() + tomorrow := now.AddDate(0, 0, 1) + tt := []struct { + testName string + inputConditions database.Condition + inputChanges []database.Change + expectedError error + expectedUpdatedRecords func() []*domain.IDPIntent + expectedUpdatedRows int64 + }{ + { + testName: "when no changes should return no changes error", + expectedError: database.ErrNoChanges, + }, + { + testName: "when no condition set should return missing condition error", + inputChanges: database.Changes{ + idpIntentRepo.SetIDPUser([]byte("not a user")), + }, + expectedError: database.NewMissingConditionError(idpIntentRepo.InstanceIDColumn()), + }, + { + testName: "when simulating SucceededEvent should update fields accordingly", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + inputChanges: database.Changes{ + idpIntentRepo.SetState(domain.IDPIntentStateSucceeded), + idpIntentRepo.SetIDPUser([]byte("update user")), + idpIntentRepo.SetIDPUserID("idp user id updated"), + idpIntentRepo.SetIDPUsername("idp username updated"), + idpIntentRepo.SetUserID("some-user-id"), + idpIntentRepo.SetIDPAccessToken([]byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`)), + idpIntentRepo.SetIDPIDToken("idp id token"), + idpIntentRepo.SetSucceededAt(now), + idpIntentRepo.SetExpiresAt(tomorrow), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn := intent1 + toReturn.IDPUser = []byte("update user") + toReturn.IDPUserID = "idp user id updated" + toReturn.IDPUsername = "idp username updated" + toReturn.UserID = "some-user-id" + toReturn.IDPAccessToken = []byte(`{"secret": "g1g4 s3cr3t 4cc3ss t0k3n"}`) + toReturn.IDPIDToken = "idp id token" + toReturn.SucceededAt = &now + toReturn.ExpiresAt = &tomorrow + toReturn.State = domain.IDPIntentStateSucceeded + return []*domain.IDPIntent{&toReturn} + }, + expectedUpdatedRows: 1, + }, + { + testName: "when simulating SAMLSucceededEvent should update fields accordingly", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + inputChanges: database.Changes{ + idpIntentRepo.SetState(domain.IDPIntentStateSucceeded), + idpIntentRepo.SetIDPUser([]byte("update user")), + idpIntentRepo.SetIDPUserID("idp user id updated"), + idpIntentRepo.SetIDPUsername("idp username updated"), + idpIntentRepo.SetUserID("some-user-id"), + idpIntentRepo.SetAssertion([]byte(`{"assertion": "val1"}`)), + idpIntentRepo.SetSucceededAt(now), + idpIntentRepo.SetExpiresAt(tomorrow), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn := intent1 + toReturn.IDPUser = []byte("update user") + toReturn.IDPUserID = "idp user id updated" + toReturn.IDPUsername = "idp username updated" + toReturn.UserID = "some-user-id" + toReturn.Assertion = []byte(`{"assertion": "val1"}`) + toReturn.SucceededAt = &now + toReturn.ExpiresAt = &tomorrow + toReturn.State = domain.IDPIntentStateSucceeded + return []*domain.IDPIntent{&toReturn} + }, + expectedUpdatedRows: 1, + }, + { + testName: "when simulating LDAPSucceededEvent should update fields accordingly", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + inputChanges: database.Changes{ + idpIntentRepo.SetState(domain.IDPIntentStateSucceeded), + idpIntentRepo.SetIDPUser([]byte("update user")), + idpIntentRepo.SetIDPUserID("idp user id updated"), + idpIntentRepo.SetIDPUsername("idp username updated"), + idpIntentRepo.SetUserID("some-user-id"), + idpIntentRepo.SetIDPEntryAttributes(marshalledAttrs), + idpIntentRepo.SetSucceededAt(now), + idpIntentRepo.SetExpiresAt(tomorrow), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn := intent1 + toReturn.IDPUser = []byte("update user") + toReturn.IDPUserID = "idp user id updated" + toReturn.IDPUsername = "idp username updated" + toReturn.UserID = "some-user-id" + toReturn.EntryAttributes = entryAttrs + toReturn.SucceededAt = &now + toReturn.ExpiresAt = &tomorrow + toReturn.State = domain.IDPIntentStateSucceeded + return []*domain.IDPIntent{&toReturn} + }, + expectedUpdatedRows: 1, + }, + { + testName: "when simulating FailedEvent should update reason, state and failedAt", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + inputChanges: database.Changes{ + idpIntentRepo.SetState(domain.IDPIntentStateFailed), + idpIntentRepo.SetFailReason("mock failure"), + idpIntentRepo.SetFailedAt(now), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn := intent1 + toReturn.FailReason = "mock failure" + toReturn.State = domain.IDPIntentStateFailed + toReturn.FailedAt = &now + return []*domain.IDPIntent{&toReturn} + }, + expectedUpdatedRows: 1, + }, + { + testName: "when simulating SAMLRequestEvent should update request ID", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + inputChanges: database.Changes{ + idpIntentRepo.SetRequestID("req-123"), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn := intent1 + toReturn.RequestID = "req-123" + return []*domain.IDPIntent{&toReturn} + }, + expectedUpdatedRows: 1, + }, + { + testName: "when updating multiple records should return updated records", + inputConditions: database.Or( + idpIntentRepo.PrimaryKeyCondition(instanceID, intentID1), + idpIntentRepo.PrimaryKeyCondition(instanceID, intentID2), + ), + inputChanges: database.Changes{ + idpIntentRepo.SetState(domain.IDPIntentStateFailed), + idpIntentRepo.SetRequestID("req-123"), + idpIntentRepo.SetFailedAt(now), + }, + expectedUpdatedRecords: func() []*domain.IDPIntent { + toReturn1, toReturn2 := intent1, intent2 + toReturn1.State = domain.IDPIntentStateFailed + toReturn1.RequestID = "req-123" + toReturn1.FailedAt = &now + toReturn2.State = domain.IDPIntentStateFailed + toReturn2.RequestID = "req-123" + toReturn2.FailedAt = &now + return []*domain.IDPIntent{&toReturn1, &toReturn2} + }, + expectedUpdatedRows: 2, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + savePoint, err := tx.Begin(t.Context()) + require.NoError(t, err) + defer func() { + err := savePoint.Rollback(t.Context()) + require.NoError(t, err) + }() + + // Test + updatedCount, err := idpIntentRepo.Update(t.Context(), savePoint, tc.inputConditions, tc.inputChanges...) + afterUpdate := time.Now() + + // Verify + assert.ErrorIs(t, err, tc.expectedError) + require.Equal(t, tc.expectedUpdatedRows, updatedCount) + if tc.expectedError == nil { + for _, expectedIntent := range tc.expectedUpdatedRecords() { + retrievedIntent, err := idpIntentRepo.Get(t.Context(), savePoint, database.WithCondition(idpIntentRepo.PrimaryKeyCondition(instanceID, expectedIntent.ID))) + require.NoError(t, err) + assert.Equal(t, expectedIntent.ID, retrievedIntent.ID) + assert.Equal(t, expectedIntent.InstanceID, retrievedIntent.InstanceID) + assert.Equal(t, expectedIntent.State, retrievedIntent.State) + assert.Equal(t, expectedIntent.SuccessURL, retrievedIntent.SuccessURL) + assert.Equal(t, expectedIntent.FailureURL, retrievedIntent.FailureURL) + assert.Equal(t, expectedIntent.CreatedAt, retrievedIntent.CreatedAt) + assert.WithinRange(t, retrievedIntent.UpdatedAt, beforeUpdate, afterUpdate) + assert.Equal(t, expectedIntent.IDPID, retrievedIntent.IDPID) + assert.Equal(t, expectedIntent.IDPUser, retrievedIntent.IDPUser) + assert.Equal(t, expectedIntent.IDPUserID, retrievedIntent.IDPUserID) + assert.Equal(t, expectedIntent.IDPUsername, retrievedIntent.IDPUsername) + assert.Equal(t, expectedIntent.UserID, retrievedIntent.UserID) + assert.Equal(t, expectedIntent.IDPAccessToken, retrievedIntent.IDPAccessToken) + assert.Equal(t, expectedIntent.IDPIDToken, retrievedIntent.IDPIDToken) + assert.Equal(t, expectedIntent.EntryAttributes, retrievedIntent.EntryAttributes) + assert.Equal(t, expectedIntent.RequestID, retrievedIntent.RequestID) + assert.Equal(t, expectedIntent.Assertion, retrievedIntent.Assertion) + if expectedIntent.State == domain.IDPIntentStateSucceeded { + require.NotNil(t, retrievedIntent.SucceededAt) + assert.WithinRange(t, *retrievedIntent.SucceededAt, beforeUpdate, afterUpdate) + require.NotNil(t, retrievedIntent.ExpiresAt) + assert.WithinRange(t, *retrievedIntent.ExpiresAt, beforeUpdate.AddDate(0, 0, 1), afterUpdate.AddDate(0, 0, 1)) + } + if expectedIntent.State == domain.IDPIntentStateFailed { + require.NotNil(t, retrievedIntent.FailedAt) + assert.WithinRange(t, *retrievedIntent.FailedAt, beforeUpdate, afterUpdate) + } + assert.Equal(t, expectedIntent.FailReason, retrievedIntent.FailReason) + } + } + }) + } +} + +func TestDeleteIDPIntent(t *testing.T) { + tx, err := pool.Begin(t.Context(), nil) + require.NoError(t, err) + defer func() { + err := tx.Rollback(t.Context()) + require.NoError(t, err) + }() + + instanceID := createInstance(t, tx) + orgID := createOrganization(t, tx, instanceID) + idpID := createIdentityProvider(t, tx, instanceID, orgID) + intentID := createIDPIntent(t, tx, instanceID, idpID) + otherIntentID := createIDPIntent(t, tx, instanceID, idpID) + createIDPIntent(t, tx, instanceID, idpID) + idpIntentRepo := repository.IDPIntentRepository() + + tt := []struct { + testName string + inputConditions database.Condition + expectedError error + expectedDeletedCount int64 + }{ + { + testName: "when PK condition not set should return missing condition error", + inputConditions: idpIntentRepo.StateCondition(domain.IDPIntentStateFailed), + expectedError: database.NewMissingConditionError(nil), + }, + { + testName: "when condition matches record should delete matching record", + inputConditions: idpIntentRepo.PrimaryKeyCondition(instanceID, intentID), + expectedDeletedCount: 1, + }, + { + testName: "when conditions matches record should delete matching records", + inputConditions: database.Or( + idpIntentRepo.PrimaryKeyCondition(instanceID, intentID), + idpIntentRepo.PrimaryKeyCondition(instanceID, otherIntentID), + ), + expectedDeletedCount: 2, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + savePoint, err := tx.Begin(t.Context()) + require.NoError(t, err) + defer func() { + err := savePoint.Rollback(t.Context()) + require.NoError(t, err) + }() + + // Test + deleteCount, err := idpIntentRepo.Delete(t.Context(), savePoint, tc.inputConditions) + + // Verify + assert.ErrorIs(t, err, tc.expectedError) + assert.Equal(t, tc.expectedDeletedCount, deleteCount) + + }) + } +} diff --git a/backend/v3/storage/database/repository/repository_test.go b/backend/v3/storage/database/repository/repository_test.go index d3b072993..8d26b96f8 100644 --- a/backend/v3/storage/database/repository/repository_test.go +++ b/backend/v3/storage/database/repository/repository_test.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "log" + "net/url" "os" "testing" + "time" "github.com/brianvoe/gofakeit/v6" + "github.com/muhlemmer/gu" "github.com/stretchr/testify/require" "github.com/zitadel/zitadel/backend/v3/domain" @@ -161,3 +164,49 @@ func createProjectGrant(t *testing.T, tx database.Transaction, instanceID, grant return projectGrant.ID } + +func createIdentityProvider(t *testing.T, tx database.Transaction, instanceID, orgID string) string { + t.Helper() + idp := domain.IdentityProvider{ + InstanceID: instanceID, + OrgID: &orgID, + ID: gofakeit.UUID(), + State: domain.IDPStateActive, + Name: gofakeit.Name(), + Type: gu.Ptr(domain.IDPTypeOIDC), + AllowCreation: true, + AllowAutoCreation: true, + AllowAutoUpdate: true, + AllowLinking: true, + StylingType: &stylingType, + Payload: []byte("{}"), + } + idpRepo := repository.IDProviderRepository() + err := idpRepo.Create(t.Context(), tx, &idp) + require.NoError(t, err) + + return idp.ID +} + +func createIDPIntent(t *testing.T, tx database.Transaction, instanceID, idpID string) string { + t.Helper() + successURL, err := url.Parse("https://example.com/success") + require.NoError(t, err) + failURL, err := url.Parse("https://example.com/fail") + require.NoError(t, err) + + intent := domain.IDPIntent{ + ID: gofakeit.UUID(), + InstanceID: instanceID, + SuccessURL: successURL, + FailureURL: failURL, + IDPID: idpID, + IDPArguments: map[string]any{"arg1": map[string]any{"k1": 1, "k2": "v2"}}, + CreatedAt: time.Now(), + } + idpIntentRepo := repository.IDPIntentRepository() + err = idpIntentRepo.Create(t.Context(), tx, &intent) + require.NoError(t, err) + + return intent.ID +} diff --git a/internal/api/grpc/user/v2/integration_test/intent_test.go b/internal/api/grpc/user/v2/integration_test/intent_test.go index a9d6b811c..f7fde1c65 100644 --- a/internal/api/grpc/user/v2/integration_test/intent_test.go +++ b/internal/api/grpc/user/v2/integration_test/intent_test.go @@ -365,9 +365,9 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "user") require.NoError(t, err) - samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", expiry) + samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", "", expiry) require.NoError(t, err) - samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", expiry) + samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", "", expiry) require.NoError(t, err) jwtSuccessfulID, jwtToken, jwtChangeDate, jwtSequence, err := sink.SuccessfulJWTIntent(Instance.ID(), jwtIdPID, "id", "", expiry) diff --git a/internal/api/grpc/user/v2beta/integration_test/user_test.go b/internal/api/grpc/user/v2beta/integration_test/user_test.go index bb2111c74..52e189bfb 100644 --- a/internal/api/grpc/user/v2beta/integration_test/user_test.go +++ b/internal/api/grpc/user/v2beta/integration_test/user_test.go @@ -2245,9 +2245,9 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { require.NoError(t, err) ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "user") require.NoError(t, err) - samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", expiry) + samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", "", expiry) require.NoError(t, err) - samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", expiry) + samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", "", expiry) require.NoError(t, err) type args struct { ctx context.Context diff --git a/internal/idp/providers/ldap/fetch_user.go b/internal/idp/providers/ldap/fetch_user.go new file mode 100644 index 000000000..1ee952578 --- /dev/null +++ b/internal/idp/providers/ldap/fetch_user.go @@ -0,0 +1,60 @@ +//go:build !integration + +package ldap + +import ( + "context" + "errors" + + "github.com/go-ldap/ldap/v3" + + "github.com/zitadel/zitadel/internal/idp" +) + +// FetchUser implements the [idp.Session] interface. +func (s *Session) FetchUser(_ context.Context) (_ idp.User, err error) { + var user *ldap.Entry + for _, server := range s.Provider.servers { + user, err = tryBind(server, + s.Provider.startTLS, + s.Provider.bindDN, + s.Provider.bindPassword, + s.Provider.baseDN, + s.Provider.getNecessaryAttributes(), + s.Provider.userObjectClasses, + s.Provider.userFilters, + s.User, + s.Password, + s.Provider.timeout, + s.Provider.rootCA) + // If there were invalid credentials or multiple users with the credentials cancel process + if err != nil && (errors.Is(err, ErrFailedLogin) || errors.Is(err, ErrNoSingleUser)) { + return nil, err + } + // If a user bind was successful and user is filled continue with login, otherwise try next server + if err == nil && user != nil { + break + } + } + if err != nil { + return nil, err + } + s.Entry = user + + return mapLDAPEntryToUser( + user, + s.Provider.idAttribute, + s.Provider.firstNameAttribute, + s.Provider.lastNameAttribute, + s.Provider.displayNameAttribute, + s.Provider.nickNameAttribute, + s.Provider.preferredUsernameAttribute, + s.Provider.emailAttribute, + s.Provider.emailVerifiedAttribute, + s.Provider.phoneAttribute, + s.Provider.phoneVerifiedAttribute, + s.Provider.preferredLanguageAttribute, + s.Provider.avatarURLAttribute, + s.Provider.profileAttribute, + ) +} diff --git a/internal/idp/providers/ldap/fetch_user_mock.go b/internal/idp/providers/ldap/fetch_user_mock.go new file mode 100644 index 000000000..70cf3cb02 --- /dev/null +++ b/internal/idp/providers/ldap/fetch_user_mock.go @@ -0,0 +1,68 @@ +//go:build integration + +package ldap + +import ( + "context" + + "github.com/brianvoe/gofakeit/v6" + "github.com/go-ldap/ldap/v3" + "golang.org/x/text/language" + + "github.com/zitadel/zitadel/internal/domain" + "github.com/zitadel/zitadel/internal/idp" +) + +const ( + FailingUser = "IAM FAIL" + FailingPsw = "test failed successfully" +) + +// FetchUser implements the [idp.Session] interface. +// +// This is a mock implementation of [idp.Session.FetchUser] that is used +// during integration tests and substitutes the real [idp.Session.FetchUser] +// implementation. +// +// This has been done to allow writing integration tests against a +// fake (external) LDAP server. +// +// The substitution/overloading is done through build tags. +// +// When the LDAP start intent is called with `username = [FailingUser]` and +// `password = [FailingPsw]`, the method return [ErrFailedLogin] to be able +// to mock an intent failed event. +func (s *Session) FetchUser(_ context.Context) (_ idp.User, err error) { + if s.User == FailingUser && s.Password == FailingPsw { + return nil, ErrFailedLogin + } + + usr := NewUser( + gofakeit.UUID(), + gofakeit.FirstName(), + gofakeit.LastName(), + gofakeit.Name(), + gofakeit.Name(), + gofakeit.Name(), + domain.EmailAddress(gofakeit.Email()), + true, + domain.PhoneNumber(gofakeit.Phone()), + true, + language.English, + gofakeit.URL(), + gofakeit.UUID(), + ) + + s.Entry = &ldap.Entry{ + DN: s.Provider.baseDN, + Attributes: []*ldap.EntryAttribute{ + {Name: "uid", Values: []string{gofakeit.UUID()}}, + {Name: "givenName", Values: []string{gofakeit.FirstName()}}, + {Name: "sn", Values: []string{gofakeit.LastName()}}, + {Name: "mail", Values: []string{gofakeit.Email()}}, + {Name: "telephoneNumber", Values: []string{gofakeit.Phone()}}, + {Name: "displayName", Values: []string{gofakeit.Name()}}, + }, + } + return usr, nil +} diff --git a/internal/idp/providers/ldap/ldap.go b/internal/idp/providers/ldap/ldap.go index 567356d41..35ae8dd1e 100644 --- a/internal/idp/providers/ldap/ldap.go +++ b/internal/idp/providers/ldap/ldap.go @@ -245,6 +245,7 @@ func (p *Provider) IsAutoUpdate() bool { return p.isAutoUpdate } +// Do not remove, used in [Session.FetchUser] @ fetch_user.go func (p *Provider) getNecessaryAttributes() []string { attributes := []string{p.userBase} if p.idAttribute != "" { diff --git a/internal/idp/providers/ldap/session.go b/internal/idp/providers/ldap/session.go index 7f205f8ca..c194ebe56 100644 --- a/internal/idp/providers/ldap/session.go +++ b/internal/idp/providers/ldap/session.go @@ -48,58 +48,11 @@ func (s *Session) PersistentParameters() map[string]any { return nil } -// FetchUser implements the [idp.Session] interface. -func (s *Session) FetchUser(_ context.Context) (_ idp.User, err error) { - var user *ldap.Entry - for _, server := range s.Provider.servers { - user, err = tryBind(server, - s.Provider.startTLS, - s.Provider.bindDN, - s.Provider.bindPassword, - s.Provider.baseDN, - s.Provider.getNecessaryAttributes(), - s.Provider.userObjectClasses, - s.Provider.userFilters, - s.User, - s.Password, - s.Provider.timeout, - s.Provider.rootCA) - // If there were invalid credentials or multiple users with the credentials cancel process - if err != nil && (errors.Is(err, ErrFailedLogin) || errors.Is(err, ErrNoSingleUser)) { - return nil, err - } - // If a user bind was successful and user is filled continue with login, otherwise try next server - if err == nil && user != nil { - break - } - } - if err != nil { - return nil, err - } - s.Entry = user - - return mapLDAPEntryToUser( - user, - s.Provider.idAttribute, - s.Provider.firstNameAttribute, - s.Provider.lastNameAttribute, - s.Provider.displayNameAttribute, - s.Provider.nickNameAttribute, - s.Provider.preferredUsernameAttribute, - s.Provider.emailAttribute, - s.Provider.emailVerifiedAttribute, - s.Provider.phoneAttribute, - s.Provider.phoneVerifiedAttribute, - s.Provider.preferredLanguageAttribute, - s.Provider.avatarURLAttribute, - s.Provider.profileAttribute, - ) -} - func (s *Session) ExpiresAt() time.Time { return time.Time{} // falls back to the default expiration time } +// Do not remove, used in [Session.FetchUser] @ fetch_user.go func tryBind( server string, startTLS bool, diff --git a/internal/integration/sink/server.go b/internal/integration/sink/server.go index 13d735fab..3ce50c1f4 100644 --- a/internal/integration/sink/server.go +++ b/internal/integration/sink/server.go @@ -11,6 +11,7 @@ import ( "net/http" "net/url" "path" + "strings" "sync" "sync/atomic" "time" @@ -108,7 +109,12 @@ func SuccessfulOIDCIntent(instanceID, idpID, idpUserID, userID string, expiry ti return resp.IntentID, resp.Token, resp.ChangeDate, resp.Sequence, nil } -func SuccessfulSAMLIntent(instanceID, idpID, idpUserID, userID string, expiry time.Time) (string, string, time.Time, uint64, error) { +// SuccessfulSAMLIntent creates a SAMLIntent and then executes the flow to put it in +// successful state. +// +// If intentID is not empty, the intent creation is skipped and only the flow part to switch +// the intent to a successful state is executed. +func SuccessfulSAMLIntent(instanceID, idpID, idpUserID, userID, intentID string, expiry time.Time) (string, string, time.Time, uint64, error) { u := url.URL{ Scheme: "http", Host: host, @@ -120,6 +126,7 @@ func SuccessfulSAMLIntent(instanceID, idpID, idpUserID, userID string, expiry ti IDPUserID: idpUserID, UserID: userID, Expiry: expiry, + IntentID: intentID, }) if err != nil { return "", "", time.Time{}, uint64(0), err @@ -341,6 +348,7 @@ type SuccessfulIntentRequest struct { IDPUserID string `json:"idp_user_id"` UserID string `json:"user_id"` Expiry time.Time `json:"expiry"` + IntentID string `json:"intent_id"` } type SuccessfulIntentResponse struct { IntentID string `json:"intent_id"` @@ -519,7 +527,10 @@ func createSuccessfulOIDCIntent(ctx context.Context, cmd *command.Commands, req } func createSuccessfulSAMLIntent(ctx context.Context, cmd *command.Commands, req *SuccessfulIntentRequest) (*SuccessfulIntentResponse, error) { - intentID, err := createIntent(ctx, cmd, req.InstanceID, req.IDPID) + intentID := strings.TrimSpace(req.IntentID) + if intentID == "" { + intentID, _ = createIntent(ctx, cmd, req.InstanceID, req.IDPID) + } writeModel, err := cmd.GetIntentWriteModel(ctx, intentID, req.InstanceID) idpUser := &saml.UserMapper{ diff --git a/internal/query/projection/idp_intent_relational.go b/internal/query/projection/idp_intent_relational.go new file mode 100644 index 000000000..9009a9172 --- /dev/null +++ b/internal/query/projection/idp_intent_relational.go @@ -0,0 +1,257 @@ +package projection + +// TODO(adlerhurst): Uncomment once users table is created and FK can be enforced + +// import ( +// "context" +// "database/sql" +// "encoding/json" + +// "github.com/zitadel/zitadel/backend/v3/domain" +// "github.com/zitadel/zitadel/backend/v3/storage/database" +// v3_sql "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/sql" +// "github.com/zitadel/zitadel/backend/v3/storage/database/repository" +// "github.com/zitadel/zitadel/internal/eventstore" +// "github.com/zitadel/zitadel/internal/eventstore/handler/v2" +// "github.com/zitadel/zitadel/internal/repository/idpintent" +// "github.com/zitadel/zitadel/internal/zerrors" +// ) + +// const ( +// IDPIntentRelationalProjectionTable = "zitadel.identity_provider_intents" +// ) + +// type idpIntentRelationalProjection struct{} + +// func (*idpIntentRelationalProjection) Name() string { +// return IDPIntentRelationalProjectionTable +// } + +// func newIDPIntentRelationalProjection(ctx context.Context, config handler.Config) *handler.Handler { +// return handler.NewHandler(ctx, &config, new(idpIntentRelationalProjection)) +// } + +// // Reducers implements [handler.Projection]. +// func (i *idpIntentRelationalProjection) Reducers() []handler.AggregateReducer { +// return []handler.AggregateReducer{ +// { +// Aggregate: idpintent.AggregateType, +// EventReducers: []handler.EventReducer{ +// {Event: idpintent.StartedEventType, Reduce: i.reduceStartedEvent}, +// {Event: idpintent.SucceededEventType, Reduce: i.reduceSucceededEvent}, +// {Event: idpintent.SAMLSucceededEventType, Reduce: i.reduceSAMLSucceededEvent}, +// {Event: idpintent.SAMLRequestEventType, Reduce: i.reduceSAMLRequestEvent}, +// {Event: idpintent.LDAPSucceededEventType, Reduce: i.reduceLDAPSucceededEvent}, +// {Event: idpintent.FailedEventType, Reduce: i.reduceFailedEvent}, +// {Event: idpintent.ConsumedEventType, Reduce: i.reduceConsumedEvent}, +// }, +// }, +// } + +// } + +// func (i *idpIntentRelationalProjection) reduceStartedEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.StartedEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-Lqj3HB", "reduce.wrong.event.type %s", idpintent.StartedEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-rirFQm", "reduce.wrong.db.pool %T", ex) +// } + +// repo := repository.IDPIntentRepository() +// return repo.Create(ctx, v3_sql.SQLTx(tx), &domain.IDPIntent{ +// ID: e.Aggregate().ID, +// InstanceID: e.Aggregate().InstanceID, +// State: domain.IDPIntentStateStarted, +// SuccessURL: e.SuccessURL, +// FailureURL: e.FailureURL, +// CreatedAt: e.CreationDate(), +// UpdatedAt: e.CreationDate(), +// IDPID: e.IDPID, +// IDPArguments: e.IDPArguments, +// }) +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.SucceededEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-hQSxj0", "reduce.wrong.event.type %s", idpintent.SucceededEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ry4tFH", "reduce.wrong.db.pool %T", ex) +// } +// idpAccessToken, err := e.IDPAccessToken.Value() +// if err != nil { +// return err +// } +// jsonIDPAccessToken, ok := idpAccessToken.([]byte) +// if !ok { +// return zerrors.ThrowInternal(nil, "HANDL-32XE1L", "reduce.convertion.json.failed") +// } +// repo := repository.IDPIntentRepository() + +// changes := []database.Change{ +// repo.SetState(domain.IDPIntentStateSucceeded), +// repo.SetIDPUser(e.IDPUser), +// repo.SetIDPUserID(e.IDPUserID), +// repo.SetIDPUsername(e.IDPUserName), +// repo.SetUserID(e.UserID), +// repo.SetIDPAccessToken(jsonIDPAccessToken), +// repo.SetIDPIDToken(e.IDPIDToken), +// repo.SetSucceededAt(e.CreationDate()), +// repo.SetExpiresAt(e.ExpiresAt), +// } + +// _, err = repo.Update( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// changes..., +// ) +// return err +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceSAMLSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.SAMLSucceededEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-t2uaiv", "reduce.wrong.event.type %s", idpintent.SAMLSucceededEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-0QGPXm", "reduce.wrong.db.pool %T", ex) +// } +// assertion, err := e.Assertion.Value() +// if err != nil { +// return err +// } +// jsonAssertion, ok := assertion.([]byte) +// if !ok { +// return zerrors.ThrowInternal(nil, "HANDL-1TFjTi", "reduce.convertion.json.failed") +// } + +// repo := repository.IDPIntentRepository() +// _, err = repo.Update( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// repo.SetState(domain.IDPIntentStateSucceeded), +// repo.SetIDPUser(e.IDPUser), +// repo.SetIDPUserID(e.IDPUserID), +// repo.SetIDPUsername(e.IDPUserName), +// repo.SetUserID(e.UserID), +// repo.SetAssertion(jsonAssertion), +// repo.SetSucceededAt(e.CreationDate()), +// repo.SetExpiresAt(e.ExpiresAt), +// ) +// return err +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceSAMLRequestEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.SAMLRequestEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-f7O6K2", "reduce.wrong.event.type %s", idpintent.SAMLRequestEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-ijgAPJ", "reduce.wrong.db.pool %T", ex) +// } + +// repo := repository.IDPIntentRepository() +// _, err := repo.Update( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// repo.SetRequestID(e.RequestID), +// ) +// return err +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceLDAPSucceededEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.LDAPSucceededEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-Gw8ddW", "reduce.wrong.event.type %s", idpintent.LDAPSucceededEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-tNp8aa", "reduce.wrong.db.pool %T", ex) +// } + +// jsonAttributes, err := json.Marshal(e.EntryAttributes) +// if err != nil { +// return zerrors.ThrowInternal(nil, "HANDL-LuvCvD", "reduce.convertion.json.failed") +// } + +// repo := repository.IDPIntentRepository() +// _, err = repo.Update( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// repo.SetState(domain.IDPIntentStateSucceeded), +// repo.SetIDPUser(e.IDPUser), +// repo.SetIDPUserID(e.IDPUserID), +// repo.SetIDPUsername(e.IDPUserName), +// repo.SetUserID(e.UserID), +// repo.SetIDPEntryAttributes(jsonAttributes), +// repo.SetSucceededAt(e.CreationDate()), +// repo.SetExpiresAt(e.ExpiresAt), +// ) +// return err +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceFailedEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.FailedEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-x3o9LZ", "reduce.wrong.event.type %s", idpintent.FailedEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-iqmR8O", "reduce.wrong.db.pool %T", ex) +// } + +// repo := repository.IDPIntentRepository() +// _, err := repo.Update( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// repo.SetState(domain.IDPIntentStateFailed), +// repo.SetFailReason(e.Reason), +// repo.SetFailedAt(e.CreatedAt()), +// ) +// return err +// }), nil +// } + +// func (i *idpIntentRelationalProjection) reduceConsumedEvent(evt eventstore.Event) (*handler.Statement, error) { +// e, ok := evt.(*idpintent.ConsumedEvent) +// if !ok { +// return nil, zerrors.ThrowInternalf(nil, "HANDL-jHZs6T", "reduce.wrong.event.type %s", idpintent.ConsumedEventType) +// } +// return handler.NewStatement(e, func(ctx context.Context, ex handler.Executer, _ string) error { +// tx, ok := ex.(*sql.Tx) +// if !ok { +// return zerrors.ThrowInvalidArgumentf(nil, "HANDL-8X9U9w", "reduce.wrong.db.pool %T", ex) +// } + +// repo := repository.IDPIntentRepository() +// _, err := repo.Delete( +// ctx, +// v3_sql.SQLTx(tx), +// repo.PrimaryKeyCondition(e.Aggregate().InstanceID, e.Aggregate().ID), +// ) +// return err +// }), nil +// } diff --git a/internal/query/projection/projection.go b/internal/query/projection/projection.go index ba7131e47..f5faf3c1e 100644 --- a/internal/query/projection/projection.go +++ b/internal/query/projection/projection.go @@ -101,6 +101,8 @@ var ( ProjectGrantRelationalProjection *handler.Handler SessionRelationalProjection *handler.Handler SettingsRelationalProjection *handler.Handler + // TODO(adlerhurst): Uncomment once users table is created and FK can be enforced + // IDPIntentRelationalProjection *handler.Handler ProjectGrantFields *handler.FieldHandler OrgDomainVerifiedFields *handler.FieldHandler @@ -230,6 +232,8 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore, AuthorizationRelationalProjection = newAuthorizationRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["authorizations_relational"])) ProjectGrantRelationalProjection = newProjectGrantRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["project_grant_relational"])) SessionRelationalProjection = newSessionRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["session_relational"])) + // TODO(adlerhurst): Uncomment once users table is created and FK can be enforced + // IDPIntentRelationalProjection = newIDPIntentRelationalProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_intent_relational"])) newProjectionsList() newFieldsList() @@ -427,5 +431,7 @@ func newProjectionsList() { AuthorizationRelationalProjection, ProjectGrantRelationalProjection, SessionRelationalProjection, + // TODO(adlerhurst): Uncomment once users table is created and FK can be enforced + // IDPIntentRelationalProjection, } }