mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 07:47:32 +00:00
feat: directly specify factors/idps on addCustomLoginPolicy and return on LoginPolicy responses (#3711)
* feat: directly specify factors on addCustomLoginPolicy and return on LoginPolicy responses * fix proto * update login policy * feat: directly specify idp on addCustomLoginPolicy and return on LoginPolicy responses * fix: tests Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
This commit is contained in:
@@ -36,6 +36,7 @@ type LoginPolicy struct {
|
||||
MFAInitSkipLifetime time.Duration
|
||||
SecondFactorCheckLifetime time.Duration
|
||||
MultiFactorCheckLifetime time.Duration
|
||||
IDPLinks []*IDPLoginPolicyLink
|
||||
}
|
||||
|
||||
type SecondFactors struct {
|
||||
@@ -160,8 +161,11 @@ func (q *Queries) LoginPolicyByID(ctx context.Context, orgID string) (*LoginPoli
|
||||
return nil, errors.ThrowInternal(err, "QUERY-scVHo", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, stmt, args...)
|
||||
return scan(row)
|
||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SWgr3", "Errors.Internal")
|
||||
}
|
||||
return scan(rows)
|
||||
}
|
||||
|
||||
func (q *Queries) DefaultLoginPolicy(ctx context.Context) (*LoginPolicy, error) {
|
||||
@@ -174,8 +178,11 @@ func (q *Queries) DefaultLoginPolicy(ctx context.Context) (*LoginPolicy, error)
|
||||
return nil, errors.ThrowInternal(err, "QUERY-t4TBK", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, stmt, args...)
|
||||
return scan(row)
|
||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SArt2", "Errors.Internal")
|
||||
}
|
||||
return scan(rows)
|
||||
}
|
||||
|
||||
func (q *Queries) SecondFactorsByOrg(ctx context.Context, orgID string) (*SecondFactors, error) {
|
||||
@@ -278,7 +285,7 @@ func (q *Queries) DefaultMultiFactors(ctx context.Context) (*MultiFactors, error
|
||||
return factors, err
|
||||
}
|
||||
|
||||
func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy, error)) {
|
||||
func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Rows) (*LoginPolicy, error)) {
|
||||
return sq.Select(
|
||||
LoginPolicyColumnOrgID.identifier(),
|
||||
LoginPolicyColumnCreationDate.identifier(),
|
||||
@@ -300,39 +307,69 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy,
|
||||
LoginPolicyColumnMFAInitSkipLifetime.identifier(),
|
||||
LoginPolicyColumnSecondFactorCheckLifetime.identifier(),
|
||||
LoginPolicyColumnMultiFacotrCheckLifetime.identifier(),
|
||||
).From(loginPolicyTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*LoginPolicy, error) {
|
||||
IDPLoginPolicyLinkIDPIDCol.identifier(),
|
||||
IDPNameCol.identifier(),
|
||||
IDPTypeCol.identifier(),
|
||||
).From(loginPolicyTable.identifier()).
|
||||
LeftJoin(join(IDPLoginPolicyLinkIDPIDCol, LoginPolicyColumnOrgID)).
|
||||
LeftJoin(join(IDPIDCol, IDPLoginPolicyLinkIDPIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*LoginPolicy, error) {
|
||||
p := new(LoginPolicy)
|
||||
secondFactors := pq.Int32Array{}
|
||||
multiFactors := pq.Int32Array{}
|
||||
defaultRedirectURI := sql.NullString{}
|
||||
err := row.Scan(
|
||||
&p.OrgID,
|
||||
&p.CreationDate,
|
||||
&p.ChangeDate,
|
||||
&p.Sequence,
|
||||
&p.AllowRegister,
|
||||
&p.AllowUsernamePassword,
|
||||
&p.AllowExternalIDPs,
|
||||
&p.ForceMFA,
|
||||
&secondFactors,
|
||||
&multiFactors,
|
||||
&p.PasswordlessType,
|
||||
&p.IsDefault,
|
||||
&p.HidePasswordReset,
|
||||
&p.IgnoreUnknownUsernames,
|
||||
&defaultRedirectURI,
|
||||
&p.PasswordCheckLifetime,
|
||||
&p.ExternalLoginCheckLifetime,
|
||||
&p.MFAInitSkipLifetime,
|
||||
&p.SecondFactorCheckLifetime,
|
||||
&p.MultiFactorCheckLifetime,
|
||||
)
|
||||
if err != nil {
|
||||
if errs.Is(err, sql.ErrNoRows) {
|
||||
return nil, errors.ThrowNotFound(err, "QUERY-QsUBJ", "Errors.LoginPolicy.NotFound")
|
||||
links := make([]*IDPLoginPolicyLink, 0)
|
||||
for rows.Next() {
|
||||
var (
|
||||
idpID = sql.NullString{}
|
||||
idpName = sql.NullString{}
|
||||
idpType = sql.NullInt16{}
|
||||
)
|
||||
err := rows.Scan(
|
||||
&p.OrgID,
|
||||
&p.CreationDate,
|
||||
&p.ChangeDate,
|
||||
&p.Sequence,
|
||||
&p.AllowRegister,
|
||||
&p.AllowUsernamePassword,
|
||||
&p.AllowExternalIDPs,
|
||||
&p.ForceMFA,
|
||||
&secondFactors,
|
||||
&multiFactors,
|
||||
&p.PasswordlessType,
|
||||
&p.IsDefault,
|
||||
&p.HidePasswordReset,
|
||||
&p.IgnoreUnknownUsernames,
|
||||
&defaultRedirectURI,
|
||||
&p.PasswordCheckLifetime,
|
||||
&p.ExternalLoginCheckLifetime,
|
||||
&p.MFAInitSkipLifetime,
|
||||
&p.SecondFactorCheckLifetime,
|
||||
&p.MultiFactorCheckLifetime,
|
||||
&idpID,
|
||||
&idpName,
|
||||
&idpType,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-YcC53", "Errors.Internal")
|
||||
}
|
||||
return nil, errors.ThrowInternal(err, "QUERY-YcC53", "Errors.Internal")
|
||||
var link IDPLoginPolicyLink
|
||||
if idpID.Valid {
|
||||
link = IDPLoginPolicyLink{IDPID: idpID.String}
|
||||
|
||||
link.IDPName = idpName.String
|
||||
//IDPType 0 is oidc so we have to set unspecified manually
|
||||
if idpType.Valid {
|
||||
link.IDPType = domain.IDPConfigType(idpType.Int16)
|
||||
} else {
|
||||
link.IDPType = domain.IDPConfigTypeUnspecified
|
||||
}
|
||||
links = append(links, &link)
|
||||
}
|
||||
}
|
||||
if p.OrgID == "" {
|
||||
return nil, errors.ThrowNotFound(nil, "QUERY-QsUBJ", "Errors.LoginPolicy.NotFound")
|
||||
}
|
||||
p.DefaultRedirectURI = defaultRedirectURI.String
|
||||
p.MultiFactors = make([]domain.MultiFactorType, len(multiFactors))
|
||||
@@ -343,6 +380,7 @@ func prepareLoginPolicyQuery() (sq.SelectBuilder, func(*sql.Row) (*LoginPolicy,
|
||||
for i, mfa := range secondFactors {
|
||||
p.SecondFactors[i] = domain.SecondFactorType(mfa)
|
||||
}
|
||||
p.IDPLinks = links
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
|
@@ -50,8 +50,15 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` projections.login_policies.external_login_check_lifetime,`+
|
||||
` projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` projections.login_policies.second_factor_check_lifetime,`+
|
||||
` projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM projections.login_policies`),
|
||||
` projections.login_policies.multi_factor_check_lifetime,`+
|
||||
` projections.idp_login_policy_links.idp_id,`+
|
||||
` projections.idps.name,`+
|
||||
` projections.idps.type`+
|
||||
` FROM projections.login_policies`+
|
||||
` LEFT JOIN projections.idp_login_policy_links ON `+
|
||||
` projections.login_policies.aggregate_id = projections.idp_login_policy_links.idp_id`+
|
||||
` LEFT JOIN projections.idps ON`+
|
||||
` projections.idp_login_policy_links.idp_id = projections.idps.id`),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
@@ -88,8 +95,15 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` projections.login_policies.external_login_check_lifetime,`+
|
||||
` projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` projections.login_policies.second_factor_check_lifetime,`+
|
||||
` projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM projections.login_policies`),
|
||||
` projections.login_policies.multi_factor_check_lifetime,`+
|
||||
` projections.idp_login_policy_links.idp_id,`+
|
||||
` projections.idps.name,`+
|
||||
` projections.idps.type`+
|
||||
` FROM projections.login_policies`+
|
||||
` LEFT JOIN projections.idp_login_policy_links ON `+
|
||||
` projections.login_policies.aggregate_id = projections.idp_login_policy_links.idp_id`+
|
||||
` LEFT JOIN projections.idps ON`+
|
||||
` projections.idp_login_policy_links.idp_id = projections.idps.id`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
"creation_date",
|
||||
@@ -111,6 +125,9 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
"mfa_init_skip_lifetime",
|
||||
"second_factor_check_lifetime",
|
||||
"multi_factor_check_lifetime",
|
||||
"idp_id",
|
||||
"name",
|
||||
"type",
|
||||
},
|
||||
[]driver.Value{
|
||||
"ro",
|
||||
@@ -133,6 +150,9 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
time.Hour * 2,
|
||||
"config1",
|
||||
"IDP",
|
||||
domain.IDPConfigTypeJWT,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -157,6 +177,13 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
MFAInitSkipLifetime: time.Hour * 2,
|
||||
SecondFactorCheckLifetime: time.Hour * 2,
|
||||
MultiFactorCheckLifetime: time.Hour * 2,
|
||||
IDPLinks: []*IDPLoginPolicyLink{
|
||||
{
|
||||
IDPID: "config1",
|
||||
IDPName: "IDP",
|
||||
IDPType: domain.IDPConfigTypeJWT,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -183,8 +210,15 @@ func Test_LoginPolicyPrepares(t *testing.T) {
|
||||
` projections.login_policies.external_login_check_lifetime,`+
|
||||
` projections.login_policies.mfa_init_skip_lifetime,`+
|
||||
` projections.login_policies.second_factor_check_lifetime,`+
|
||||
` projections.login_policies.multi_factor_check_lifetime`+
|
||||
` FROM projections.login_policies`),
|
||||
` projections.login_policies.multi_factor_check_lifetime,`+
|
||||
` projections.idp_login_policy_links.idp_id,`+
|
||||
` projections.idps.name,`+
|
||||
` projections.idps.type`+
|
||||
` FROM projections.login_policies`+
|
||||
` LEFT JOIN projections.idp_login_policy_links ON `+
|
||||
` projections.login_policies.aggregate_id = projections.idp_login_policy_links.idp_id`+
|
||||
` LEFT JOIN projections.idps ON`+
|
||||
` projections.idp_login_policy_links.idp_id = projections.idps.id`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
|
@@ -87,7 +87,7 @@ func NewAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
||||
crdb.NewColumn(AppAPIConfigColumnClientSecret, crdb.ColumnTypeJSONB, crdb.Nullable()),
|
||||
crdb.NewColumn(AppAPIConfigColumnAuthMethod, crdb.ColumnTypeEnum),
|
||||
},
|
||||
crdb.NewPrimaryKey(AppAPIConfigColumnAppID),
|
||||
crdb.NewPrimaryKey(AppAPIConfigColumnAppID, AppAPIConfigColumnInstanceID),
|
||||
appAPITableSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_api_ref_apps")),
|
||||
crdb.WithIndex(crdb.NewIndex("client_id_idx", []string{AppAPIConfigColumnClientID})),
|
||||
|
@@ -76,7 +76,7 @@ func NewIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
||||
crdb.NewColumn(IDPStylingTypeCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPOwnerTypeCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPAutoRegisterCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
crdb.NewColumn(IDPTypeCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPTypeCol, crdb.ColumnTypeEnum, crdb.Nullable()),
|
||||
},
|
||||
crdb.NewPrimaryKey(IDPIDCol, IDPInstanceIDCol),
|
||||
crdb.WithIndex(crdb.NewIndex("ro_idx", []string{IDPResourceOwnerCol})),
|
||||
@@ -92,9 +92,9 @@ func NewIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
||||
crdb.NewColumn(OIDCConfigDisplayNameMappingCol, crdb.ColumnTypeEnum, crdb.Nullable()),
|
||||
crdb.NewColumn(OIDCConfigUsernameMappingCol, crdb.ColumnTypeEnum, crdb.Nullable()),
|
||||
crdb.NewColumn(OIDCConfigAuthorizationEndpointCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(OIDCConfigTokenEndpointCol, crdb.ColumnTypeEnum, crdb.Nullable()),
|
||||
crdb.NewColumn(OIDCConfigTokenEndpointCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
},
|
||||
crdb.NewPrimaryKey(OIDCConfigIDPIDCol),
|
||||
crdb.NewPrimaryKey(OIDCConfigIDPIDCol, OIDCConfigInstanceIDCol),
|
||||
IDPOIDCSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_oidc_ref_idp")),
|
||||
),
|
||||
@@ -106,7 +106,7 @@ func NewIDPProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
||||
crdb.NewColumn(JWTConfigHeaderNameCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(JWTConfigEndpointCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
},
|
||||
crdb.NewPrimaryKey(JWTConfigIDPIDCol),
|
||||
crdb.NewPrimaryKey(JWTConfigIDPIDCol, JWTConfigInstanceIDCol),
|
||||
IDPJWTSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_jwt_ref_idp")),
|
||||
),
|
||||
|
@@ -60,7 +60,7 @@ func NewSMSConfigProjection(ctx context.Context, config crdb.StatementHandlerCon
|
||||
crdb.NewColumn(SMSTwilioConfigColumnSenderNumber, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(SMSTwilioConfigColumnToken, crdb.ColumnTypeJSONB),
|
||||
},
|
||||
crdb.NewPrimaryKey(SMSTwilioConfigColumnSMSID),
|
||||
crdb.NewPrimaryKey(SMSTwilioConfigColumnSMSID, SMSTwilioColumnInstanceID),
|
||||
smsTwilioTableSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_twilio_ref_sms")),
|
||||
),
|
||||
|
Reference in New Issue
Block a user