Files
zitadel/backend/v3/domain/idp_intent.go
T
4936bdf2c9 feat(rt): IDP Intents Relational Table (#11374)
# Which Problems Are Solved

In the context of moving our datastore to relational tables, Identity
Provider Intents have no definition of a relational table nor any DB API
that can be used to store the IDP intents as relational objects.

# How the Problems Are Solved

The PR follows the guidelines left in #11190

- A table `zitadel.identity_provider_intents` is created: it defines its
relational constraints (foreign keys) with the other tables, as well as
an ENUM to represent the state of the intent.
- An IDP Intent repository has been created, which offers CRUD
operations implemented as `Create`, `Get`, `Update` and `Delete` methods
for the IDP intent.
- The repository also defines all columns and conditions useful for
performing DB operations on the IDP intents.
- DB mocks have been added as well to ease testing on the `domain`
package.
- Reduction functions have been implemented for the existing IDP events
so to keep the relational table in sync with the event store.

# Additional Changes

To allow testing LDAP intent flow, the `Session.FetchUser()` method has
been extracted to a separate file. A corresponding mock has been created
as well in `fetch_user_mock.go`. The files are mutually excluded and
added at build time through go build tags: the mock is added when the
`integration` tag is specified, while the real implementation is added
when the same tag IS NOT added to the build tags.

# Additional Context

- Closes #11190

---------

Co-authored-by: Livio Spring <[email protected]>
Co-authored-by: Silvan <[email protected]>
2026-02-05 03:44:07 +00:00

175 lines
8.6 KiB
Go

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)
}