feat: add exclusion of criteria for active idp query (#9040)

# Which Problems Are Solved

To list IDPs for potential linking, we need to filter them. The
GetActiveIdentityProviderResponse should therefore be extended to
provide the IDPConfig or information about whether the IDP is allowed to
be linked or created.

# How the Problems Are Solved

Add parameters to the request to exclude CreationDisallowed and/or
LinkingDisallowed in the query.

# Additional Changes

Added integration tests for the GetGetActiveIdentityProvider endpoint.

# Additional Context

Closes #8981

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2024-12-18 17:19:05 +01:00
committed by GitHub
parent da706a8b30
commit 870e3b1b26
11 changed files with 494 additions and 32 deletions

View File

@@ -96,7 +96,7 @@ func configToPb(config *query.IDPTemplate) *idp_pb.IDPConfig {
IsCreationAllowed: config.IsCreationAllowed, IsCreationAllowed: config.IsCreationAllowed,
IsAutoCreation: config.IsAutoCreation, IsAutoCreation: config.IsAutoCreation,
IsAutoUpdate: config.IsAutoUpdate, IsAutoUpdate: config.IsAutoUpdate,
AutoLinking: autoLinkingOptionToPb(config.AutoLinking), AutoLinking: AutoLinkingOptionToPb(config.AutoLinking),
}, },
} }
if config.OAuthIDPTemplate != nil { if config.OAuthIDPTemplate != nil {
@@ -150,7 +150,7 @@ func configToPb(config *query.IDPTemplate) *idp_pb.IDPConfig {
return idpConfig return idpConfig
} }
func autoLinkingOptionToPb(linking domain.AutoLinkingOption) idp_pb.AutoLinkingOption { func AutoLinkingOptionToPb(linking domain.AutoLinkingOption) idp_pb.AutoLinkingOption {
switch linking { switch linking {
case domain.AutoLinkingOptionUnspecified: case domain.AutoLinkingOptionUnspecified:
return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED

View File

@@ -7,11 +7,15 @@ import (
"testing" "testing"
"time" "time"
"github.com/brianvoe/gofakeit/v6"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/integration" "github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/idp"
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2" object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
) )
@@ -178,3 +182,281 @@ func TestServer_SetSecuritySettings(t *testing.T) {
}) })
} }
} }
func idpResponse(id, name string, linking, creation, autoCreation, autoUpdate bool, autoLinking idp_pb.AutoLinkingOption) *settings.IdentityProvider {
return &settings.IdentityProvider{
Id: id,
Name: name,
Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OAUTH,
Options: &idp_pb.Options{
IsLinkingAllowed: linking,
IsCreationAllowed: creation,
IsAutoCreation: autoCreation,
IsAutoUpdate: autoUpdate,
AutoLinking: autoLinking,
},
}
}
func TestServer_GetActiveIdentityProviders(t *testing.T) {
instance := integration.NewInstance(CTX)
isolatedIAMOwnerCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
instance.AddGenericOAuthProvider(isolatedIAMOwnerCTX, gofakeit.AppName()) // inactive
idpActiveName := gofakeit.AppName()
idpActiveResp := instance.AddGenericOAuthProvider(isolatedIAMOwnerCTX, idpActiveName)
instance.AddProviderToDefaultLoginPolicy(isolatedIAMOwnerCTX, idpActiveResp.GetId())
idpActiveResponse := idpResponse(idpActiveResp.GetId(), idpActiveName, true, true, true, true, idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
idpLinkingDisallowedName := gofakeit.AppName()
idpLinkingDisallowedResp := instance.AddGenericOAuthProviderWithOptions(isolatedIAMOwnerCTX, idpLinkingDisallowedName, false, true, true, idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
instance.AddProviderToDefaultLoginPolicy(isolatedIAMOwnerCTX, idpLinkingDisallowedResp.GetId())
idpLinkingDisallowedResponse := idpResponse(idpLinkingDisallowedResp.GetId(), idpLinkingDisallowedName, false, true, true, true, idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
idpCreationDisallowedName := gofakeit.AppName()
idpCreationDisallowedResp := instance.AddGenericOAuthProviderWithOptions(isolatedIAMOwnerCTX, idpCreationDisallowedName, true, false, true, idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
instance.AddProviderToDefaultLoginPolicy(isolatedIAMOwnerCTX, idpCreationDisallowedResp.GetId())
idpCreationDisallowedResponse := idpResponse(idpCreationDisallowedResp.GetId(), idpCreationDisallowedName, true, false, true, true, idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
idpNoAutoCreationName := gofakeit.AppName()
idpNoAutoCreationResp := instance.AddGenericOAuthProviderWithOptions(isolatedIAMOwnerCTX, idpNoAutoCreationName, true, true, false, idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
instance.AddProviderToDefaultLoginPolicy(isolatedIAMOwnerCTX, idpNoAutoCreationResp.GetId())
idpNoAutoCreationResponse := idpResponse(idpNoAutoCreationResp.GetId(), idpNoAutoCreationName, true, true, false, true, idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
idpNoAutoLinkingName := gofakeit.AppName()
idpNoAutoLinkingResp := instance.AddGenericOAuthProviderWithOptions(isolatedIAMOwnerCTX, idpNoAutoLinkingName, true, true, true, idp.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED)
instance.AddProviderToDefaultLoginPolicy(isolatedIAMOwnerCTX, idpNoAutoLinkingResp.GetId())
idpNoAutoLinkingResponse := idpResponse(idpNoAutoLinkingResp.GetId(), idpNoAutoLinkingName, true, true, true, true, idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED)
type args struct {
ctx context.Context
req *settings.GetActiveIdentityProvidersRequest
}
tests := []struct {
name string
args args
want *settings.GetActiveIdentityProvidersResponse
wantErr bool
}{
{
name: "permission error",
args: args{
ctx: instance.WithAuthorization(CTX, integration.UserTypeLogin),
req: &settings.GetActiveIdentityProvidersRequest{},
},
wantErr: true,
},
{
name: "success, all",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 5,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
idpLinkingDisallowedResponse,
idpCreationDisallowedResponse,
idpNoAutoCreationResponse,
idpNoAutoLinkingResponse,
},
},
},
{
name: "success, exclude linking disallowed",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
LinkingAllowed: gu.Ptr(true),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 4,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
idpCreationDisallowedResponse,
idpNoAutoCreationResponse,
idpNoAutoLinkingResponse,
},
},
},
{
name: "success, only linking disallowed",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
LinkingAllowed: gu.Ptr(false),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpLinkingDisallowedResponse,
},
},
},
{
name: "success, exclude creation disallowed",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
CreationAllowed: gu.Ptr(true),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 4,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
idpLinkingDisallowedResponse,
idpNoAutoCreationResponse,
idpNoAutoLinkingResponse,
},
},
},
{
name: "success, only creation disallowed",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
CreationAllowed: gu.Ptr(false),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpCreationDisallowedResponse,
},
},
},
{
name: "success, auto creation",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
AutoCreation: gu.Ptr(true),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 4,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
idpLinkingDisallowedResponse,
idpCreationDisallowedResponse,
idpNoAutoLinkingResponse,
},
},
},
{
name: "success, no auto creation",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
AutoCreation: gu.Ptr(false),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpNoAutoCreationResponse,
},
},
},
{
name: "success, auto linking",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
AutoLinking: gu.Ptr(true),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 4,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
idpLinkingDisallowedResponse,
idpCreationDisallowedResponse,
idpNoAutoCreationResponse,
},
},
},
{
name: "success, no auto linking",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
AutoLinking: gu.Ptr(false),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpNoAutoLinkingResponse,
},
},
},
{
name: "success, exclude all",
args: args{
ctx: isolatedIAMOwnerCTX,
req: &settings.GetActiveIdentityProvidersRequest{
LinkingAllowed: gu.Ptr(true),
CreationAllowed: gu.Ptr(true),
AutoCreation: gu.Ptr(true),
AutoLinking: gu.Ptr(true),
},
},
want: &settings.GetActiveIdentityProvidersResponse{
Details: &object_pb.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
IdentityProviders: []*settings.IdentityProvider{
idpActiveResponse,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(tt.args.ctx, time.Minute)
assert.EventuallyWithT(t, func(ct *assert.CollectT) {
got, err := instance.Client.SettingsV2.GetActiveIdentityProviders(tt.args.ctx, tt.args.req)
if tt.wantErr {
assert.Error(ct, err)
return
}
if !assert.NoError(ct, err) {
return
}
for i, result := range tt.want.GetIdentityProviders() {
assert.EqualExportedValues(ct, result, got.GetIdentityProviders()[i])
}
integration.AssertListDetails(ct, tt.want, got)
}, retryDuration, tick)
})
}
}

View File

@@ -120,7 +120,12 @@ func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockou
} }
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) { func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) {
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false) queries, err := activeIdentityProvidersToQuery(req)
if err != nil {
return nil, err
}
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{Queries: queries}, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -131,6 +136,43 @@ func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.G
}, nil }, nil
} }
func activeIdentityProvidersToQuery(req *settings.GetActiveIdentityProvidersRequest) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, 0, 4)
if req.CreationAllowed != nil {
creationQuery, err := query.NewIDPTemplateIsCreationAllowedSearchQuery(*req.CreationAllowed)
if err != nil {
return nil, err
}
q = append(q, creationQuery)
}
if req.LinkingAllowed != nil {
creationQuery, err := query.NewIDPTemplateIsLinkingAllowedSearchQuery(*req.LinkingAllowed)
if err != nil {
return nil, err
}
q = append(q, creationQuery)
}
if req.AutoCreation != nil {
creationQuery, err := query.NewIDPTemplateIsAutoCreationSearchQuery(*req.AutoCreation)
if err != nil {
return nil, err
}
q = append(q, creationQuery)
}
if req.AutoLinking != nil {
compare := query.NumberEquals
if *req.AutoLinking {
compare = query.NumberNotEquals
}
creationQuery, err := query.NewIDPTemplateAutoLinkingSearchQuery(0, compare)
if err != nil {
return nil, err
}
q = append(q, creationQuery)
}
return q, nil
}
func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralSettingsRequest) (*settings.GetGeneralSettingsResponse, error) { func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralSettingsRequest) (*settings.GetGeneralSettingsResponse, error) {
instance := authz.GetInstance(ctx) instance := authz.GetInstance(ctx)
return &settings.GetGeneralSettingsResponse{ return &settings.GetGeneralSettingsResponse{

View File

@@ -5,9 +5,11 @@ import (
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
idp_api "github.com/zitadel/zitadel/internal/api/grpc/idp/v2"
"github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
) )
@@ -189,6 +191,13 @@ func identityProviderToPb(idp *query.IDPLoginPolicyLink) *settings.IdentityProvi
Id: idp.IDPID, Id: idp.IDPID,
Name: domain.IDPName(idp.IDPName, idp.IDPType), Name: domain.IDPName(idp.IDPName, idp.IDPType),
Type: idpTypeToPb(idp.IDPType), Type: idpTypeToPb(idp.IDPType),
Options: &idp_pb.Options{
IsLinkingAllowed: idp.IsLinkingAllowed,
IsCreationAllowed: idp.IsCreationAllowed,
IsAutoCreation: idp.IsAutoCreation,
IsAutoUpdate: idp.IsAutoUpdate,
AutoLinking: idp_api.AutoLinkingOptionToPb(idp.AutoLinking),
},
} }
} }

View File

@@ -16,6 +16,7 @@ import (
"github.com/zitadel/zitadel/internal/database" "github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/pkg/grpc/idp/v2"
"github.com/zitadel/zitadel/pkg/grpc/settings/v2" "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
) )
@@ -382,14 +383,24 @@ func Test_lockoutSettingsToPb(t *testing.T) {
func Test_identityProvidersToPb(t *testing.T) { func Test_identityProvidersToPb(t *testing.T) {
arg := []*query.IDPLoginPolicyLink{ arg := []*query.IDPLoginPolicyLink{
{ {
IDPID: "1", IDPID: "1",
IDPName: "foo", IDPName: "foo",
IDPType: domain.IDPTypeOIDC, IDPType: domain.IDPTypeOIDC,
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: domain.AutoLinkingOptionUsername,
}, },
{ {
IDPID: "2", IDPID: "2",
IDPName: "bar", IDPName: "bar",
IDPType: domain.IDPTypeGitHub, IDPType: domain.IDPTypeGitHub,
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: domain.AutoLinkingOptionEmail,
}, },
} }
want := []*settings.IdentityProvider{ want := []*settings.IdentityProvider{
@@ -397,11 +408,25 @@ func Test_identityProvidersToPb(t *testing.T) {
Id: "1", Id: "1",
Name: "foo", Name: "foo",
Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OIDC, Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OIDC,
Options: &idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
},
}, },
{ {
Id: "2", Id: "2",
Name: "bar", Name: "bar",
Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB, Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB,
Options: &idp.Options{
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL,
},
}, },
} }
got := identityProvidersToPb(arg) got := identityProvidersToPb(arg)

View File

@@ -379,7 +379,18 @@ func (i *Instance) SetUserPassword(ctx context.Context, userID, password string,
return resp.GetDetails() return resp.GetDetails()
} }
func (i *Instance) AddProviderToDefaultLoginPolicy(ctx context.Context, id string) {
_, err := i.Client.Admin.AddIDPToLoginPolicy(ctx, &admin.AddIDPToLoginPolicyRequest{
IdpId: id,
})
logging.OnError(err).Panic("add provider to default login policy")
}
func (i *Instance) AddGenericOAuthProvider(ctx context.Context, name string) *admin.AddGenericOAuthProviderResponse { func (i *Instance) AddGenericOAuthProvider(ctx context.Context, name string) *admin.AddGenericOAuthProviderResponse {
return i.AddGenericOAuthProviderWithOptions(ctx, name, true, true, true, idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME)
}
func (i *Instance) AddGenericOAuthProviderWithOptions(ctx context.Context, name string, isLinkingAllowed, isCreationAllowed, isAutoCreation bool, autoLinking idp.AutoLinkingOption) *admin.AddGenericOAuthProviderResponse {
resp, err := i.Client.Admin.AddGenericOAuthProvider(ctx, &admin.AddGenericOAuthProviderRequest{ resp, err := i.Client.Admin.AddGenericOAuthProvider(ctx, &admin.AddGenericOAuthProviderRequest{
Name: name, Name: name,
ClientId: "clientID", ClientId: "clientID",
@@ -390,11 +401,11 @@ func (i *Instance) AddGenericOAuthProvider(ctx context.Context, name string) *ad
Scopes: []string{"openid", "profile", "email"}, Scopes: []string{"openid", "profile", "email"},
IdAttribute: "id", IdAttribute: "id",
ProviderOptions: &idp.Options{ ProviderOptions: &idp.Options{
IsLinkingAllowed: true, IsLinkingAllowed: isLinkingAllowed,
IsCreationAllowed: true, IsCreationAllowed: isCreationAllowed,
IsAutoCreation: true, IsAutoCreation: isAutoCreation,
IsAutoUpdate: true, IsAutoUpdate: true,
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME, AutoLinking: autoLinking,
}, },
}) })
logging.OnError(err).Panic("create generic OAuth idp") logging.OnError(err).Panic("create generic OAuth idp")

View File

@@ -15,10 +15,15 @@ import (
) )
type IDPLoginPolicyLink struct { type IDPLoginPolicyLink struct {
IDPID string IDPID string
IDPName string IDPName string
IDPType domain.IDPType IDPType domain.IDPType
OwnerType domain.IdentityProviderType OwnerType domain.IdentityProviderType
IsCreationAllowed bool
IsLinkingAllowed bool
IsAutoCreation bool
IsAutoUpdate bool
AutoLinking domain.AutoLinkingOption
} }
type IDPLoginPolicyLinks struct { type IDPLoginPolicyLinks struct {
@@ -127,6 +132,11 @@ func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase, re
IDPTemplateNameCol.identifier(), IDPTemplateNameCol.identifier(),
IDPTemplateTypeCol.identifier(), IDPTemplateTypeCol.identifier(),
IDPTemplateOwnerTypeCol.identifier(), IDPTemplateOwnerTypeCol.identifier(),
IDPTemplateIsCreationAllowedCol.identifier(),
IDPTemplateIsLinkingAllowedCol.identifier(),
IDPTemplateIsAutoCreationCol.identifier(),
IDPTemplateIsAutoUpdateCol.identifier(),
IDPTemplateAutoLinkingCol.identifier(),
countColumn.identifier()). countColumn.identifier()).
From(idpLoginPolicyLinkTable.identifier()). From(idpLoginPolicyLinkTable.identifier()).
LeftJoin(join(IDPTemplateIDCol, IDPLoginPolicyLinkIDPIDCol)). LeftJoin(join(IDPTemplateIDCol, IDPLoginPolicyLinkIDPIDCol)).
@@ -141,29 +151,60 @@ func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase, re
var count uint64 var count uint64
for rows.Next() { for rows.Next() {
var ( var (
idpName = sql.NullString{} idpName = sql.NullString{}
idpType = sql.NullInt16{} idpType = sql.NullInt16{}
idpOwnerType = sql.NullInt16{} idpOwnerType = sql.NullInt16{}
link = new(IDPLoginPolicyLink) link = new(IDPLoginPolicyLink)
isCreationAllowed = sql.NullBool{}
isLinkingAllowed = sql.NullBool{}
isAutoCreation = sql.NullBool{}
isAutoUpdate = sql.NullBool{}
autoLinking = sql.NullInt16{}
) )
err := rows.Scan( err := rows.Scan(
&link.IDPID, &link.IDPID,
&idpName, &idpName,
&idpType, &idpType,
&idpOwnerType, &idpOwnerType,
&isCreationAllowed,
&isLinkingAllowed,
&isAutoCreation,
&isAutoUpdate,
&autoLinking,
&count, &count,
) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
link.IDPName = idpName.String if idpName.Valid {
link.IDPName = idpName.String
}
//IDPType 0 is oidc so we have to set unspecified manually //IDPType 0 is oidc so we have to set unspecified manually
if idpType.Valid { if idpType.Valid {
link.IDPType = domain.IDPType(idpType.Int16) link.IDPType = domain.IDPType(idpType.Int16)
} else { } else {
link.IDPType = domain.IDPTypeUnspecified link.IDPType = domain.IDPTypeUnspecified
} }
link.OwnerType = domain.IdentityProviderType(idpOwnerType.Int16) if idpOwnerType.Valid {
link.OwnerType = domain.IdentityProviderType(idpOwnerType.Int16)
}
if isCreationAllowed.Valid {
link.IsCreationAllowed = isCreationAllowed.Bool
}
if isLinkingAllowed.Valid {
link.IsLinkingAllowed = isLinkingAllowed.Bool
}
if isAutoCreation.Valid {
link.IsAutoCreation = isAutoCreation.Bool
}
if isAutoUpdate.Valid {
link.IsAutoUpdate = isAutoUpdate.Bool
}
if autoLinking.Valid {
link.AutoLinking = domain.AutoLinkingOption(autoLinking.Int16)
} else {
link.AutoLinking = domain.AutoLinkingOptionUnspecified
}
links = append(links, link) links = append(links, link)
} }

View File

@@ -19,6 +19,11 @@ var (
` projections.idp_templates6.name,` + ` projections.idp_templates6.name,` +
` projections.idp_templates6.type,` + ` projections.idp_templates6.type,` +
` projections.idp_templates6.owner_type,` + ` projections.idp_templates6.owner_type,` +
` projections.idp_templates6.is_creation_allowed,` +
` projections.idp_templates6.is_linking_allowed,` +
` projections.idp_templates6.is_auto_creation,` +
` projections.idp_templates6.is_auto_update,` +
` projections.idp_templates6.auto_linking,` +
` COUNT(*) OVER ()` + ` COUNT(*) OVER ()` +
` FROM projections.idp_login_policy_links5` + ` FROM projections.idp_login_policy_links5` +
` LEFT JOIN projections.idp_templates6 ON projections.idp_login_policy_links5.idp_id = projections.idp_templates6.id AND projections.idp_login_policy_links5.instance_id = projections.idp_templates6.instance_id` + ` LEFT JOIN projections.idp_templates6 ON projections.idp_login_policy_links5.idp_id = projections.idp_templates6.id AND projections.idp_login_policy_links5.instance_id = projections.idp_templates6.instance_id` +
@@ -31,6 +36,11 @@ var (
"name", "name",
"type", "type",
"owner_type", "owner_type",
"is_creation_allowed",
"is_linking_allowed",
"is_auto_creation",
"is_auto_update",
"auto_linking",
"count", "count",
} }
) )
@@ -61,6 +71,11 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
"idp-name", "idp-name",
domain.IDPTypeJWT, domain.IDPTypeJWT,
domain.IdentityProviderTypeSystem, domain.IdentityProviderTypeSystem,
true,
true,
true,
true,
domain.AutoLinkingOptionUsername,
}, },
}, },
), ),
@@ -71,10 +86,15 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
}, },
Links: []*IDPLoginPolicyLink{ Links: []*IDPLoginPolicyLink{
{ {
IDPID: "idp-id", IDPID: "idp-id",
IDPName: "idp-name", IDPName: "idp-name",
IDPType: domain.IDPTypeJWT, IDPType: domain.IDPTypeJWT,
OwnerType: domain.IdentityProviderTypeSystem, OwnerType: domain.IdentityProviderTypeSystem,
IsCreationAllowed: true,
IsLinkingAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
AutoLinking: domain.AutoLinkingOptionUsername,
}, },
}, },
}, },
@@ -94,6 +114,11 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
nil, nil,
nil, nil,
nil, nil,
false,
false,
false,
false,
0,
}, },
}, },
), ),
@@ -104,9 +129,14 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
}, },
Links: []*IDPLoginPolicyLink{ Links: []*IDPLoginPolicyLink{
{ {
IDPID: "idp-id", IDPID: "idp-id",
IDPName: "", IDPName: "",
IDPType: domain.IDPTypeUnspecified, IDPType: domain.IDPTypeUnspecified,
IsCreationAllowed: false,
IsLinkingAllowed: false,
IsAutoCreation: false,
IsAutoUpdate: false,
AutoLinking: domain.AutoLinkingOptionUnspecified,
}, },
}, },
}, },

View File

@@ -825,6 +825,22 @@ func NewIDPTemplateResourceOwnerListSearchQuery(ids ...string) (SearchQuery, err
return NewListQuery(IDPTemplateResourceOwnerCol, list, ListIn) return NewListQuery(IDPTemplateResourceOwnerCol, list, ListIn)
} }
func NewIDPTemplateIsCreationAllowedSearchQuery(value bool) (SearchQuery, error) {
return NewBoolQuery(IDPTemplateIsCreationAllowedCol, value)
}
func NewIDPTemplateIsLinkingAllowedSearchQuery(value bool) (SearchQuery, error) {
return NewBoolQuery(IDPTemplateIsLinkingAllowedCol, value)
}
func NewIDPTemplateIsAutoCreationSearchQuery(value bool) (SearchQuery, error) {
return NewBoolQuery(IDPTemplateIsAutoCreationCol, value)
}
func NewIDPTemplateAutoLinkingSearchQuery(value int, method NumberComparison) (SearchQuery, error) {
return NewNumberQuery(IDPTemplateAutoLinkingCol, value, method)
}
func (q *IDPTemplateSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder { func (q *IDPTemplateSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
query = q.SearchRequest.toQuery(query) query = q.SearchRequest.toQuery(query)
for _, q := range q.Queries { for _, q := range q.Queries {

View File

@@ -6,6 +6,7 @@ option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2;settings";
import "protoc-gen-openapiv2/options/annotations.proto"; import "protoc-gen-openapiv2/options/annotations.proto";
import "zitadel/settings/v2/settings.proto"; import "zitadel/settings/v2/settings.proto";
import "zitadel/idp/v2/idp.proto";
import "google/protobuf/duration.proto"; import "google/protobuf/duration.proto";
message LoginSettings { message LoginSettings {
@@ -134,6 +135,7 @@ message IdentityProvider {
string id = 1; string id = 1;
string name = 2; string name = 2;
IdentityProviderType type = 3; IdentityProviderType type = 3;
zitadel.idp.v2.Options options = 4;
} }
enum IdentityProviderType { enum IdentityProviderType {

View File

@@ -324,7 +324,7 @@ service SettingsService {
}; };
} }
// Get the security settings // Get the security settings
rpc GetSecuritySettings(GetSecuritySettingsRequest) returns (GetSecuritySettingsResponse) { rpc GetSecuritySettings(GetSecuritySettingsRequest) returns (GetSecuritySettingsResponse) {
option (google.api.http) = { option (google.api.http) = {
get: "/v2/settings/security"; get: "/v2/settings/security";
@@ -343,7 +343,7 @@ service SettingsService {
}; };
} }
// Set the security settings // Set the security settings
rpc SetSecuritySettings(SetSecuritySettingsRequest) returns (SetSecuritySettingsResponse) { rpc SetSecuritySettings(SetSecuritySettingsRequest) returns (SetSecuritySettingsResponse) {
option (google.api.http) = { option (google.api.http) = {
put: "/v2/policies/security"; put: "/v2/policies/security";
@@ -429,6 +429,10 @@ message GetLockoutSettingsResponse {
message GetActiveIdentityProvidersRequest { message GetActiveIdentityProvidersRequest {
zitadel.object.v2.RequestContext ctx = 1; zitadel.object.v2.RequestContext ctx = 1;
optional bool creation_allowed = 2;
optional bool linking_allowed = 3;
optional bool auto_creation = 4;
optional bool auto_linking = 5;
} }
message GetActiveIdentityProvidersResponse { message GetActiveIdentityProvidersResponse {