mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:07:31 +00:00
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:
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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{
|
||||||
|
@@ -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),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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")
|
||||||
|
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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 {
|
||||||
|
Reference in New Issue
Block a user