From c9face4ea4536a17f51b9cad3da6a559a7417108 Mon Sep 17 00:00:00 2001 From: Silvan Date: Wed, 8 Dec 2021 14:49:19 +0100 Subject: [PATCH] feat(queries): login policy idp links (#2767) * fix(idp): set type in projection * correct table * user idp links * refactor: user idp link query * add not null constraint * refactor: idp user links * rename file * fix(idp): correct resource owner * refactor: rename test * fix(query): implement idp login policy links * unify naming of idp links * test prepare * fix(api): convert idp type * rename migration --- internal/api/grpc/admin/idp.go | 6 +- internal/api/grpc/admin/login_policy.go | 8 +- .../api/grpc/admin/login_policy_converter.go | 16 +-- internal/api/grpc/auth/idp.go | 10 +- internal/api/grpc/auth/idp_converter.go | 6 +- internal/api/grpc/idp/converter.go | 29 ++-- internal/api/grpc/management/idp.go | 4 + internal/api/grpc/management/policy_login.go | 6 +- .../grpc/management/policy_login_converter.go | 16 +-- internal/api/grpc/management/user.go | 2 +- .../api/grpc/management/user_converter.go | 8 +- internal/query/idp_login_policy_link.go | 135 ++++++++++++++++++ internal/query/idp_login_policy_link_test.go | 121 ++++++++++++++++ .../{user_idp_link.go => idp_user_link.go} | 28 ++-- ...idp_link_test.go => idp_user_link_test.go} | 30 ++-- 15 files changed, 336 insertions(+), 89 deletions(-) create mode 100644 internal/query/idp_login_policy_link.go create mode 100644 internal/query/idp_login_policy_link_test.go rename internal/query/{user_idp_link.go => idp_user_link.go} (82%) rename internal/query/{user_idp_link_test.go => idp_user_link_test.go} (84%) diff --git a/internal/api/grpc/admin/idp.go b/internal/api/grpc/admin/idp.go index c0f6e9b2c..74d4b9625 100644 --- a/internal/api/grpc/admin/idp.go +++ b/internal/api/grpc/admin/idp.go @@ -3,14 +3,14 @@ package admin import ( "context" - "github.com/caos/zitadel/internal/api/authz" idp_grpc "github.com/caos/zitadel/internal/api/grpc/idp" object_pb "github.com/caos/zitadel/internal/api/grpc/object" + "github.com/caos/zitadel/internal/domain" admin_pb "github.com/caos/zitadel/pkg/grpc/admin" ) func (s *Server) GetIDPByID(ctx context.Context, req *admin_pb.GetIDPByIDRequest) (*admin_pb.GetIDPByIDResponse, error) { - idp, err := s.query.IDPByIDAndResourceOwner(ctx, req.Id, authz.GetCtxData(ctx).OrgID) + idp, err := s.query.IDPByIDAndResourceOwner(ctx, req.Id, domain.IAMID) if err != nil { return nil, err } @@ -22,7 +22,7 @@ func (s *Server) ListIDPs(ctx context.Context, req *admin_pb.ListIDPsRequest) (* if err != nil { return nil, err } - resp, err := s.query.SearchIDPs(ctx, authz.GetCtxData(ctx).OrgID, queries) + resp, err := s.query.SearchIDPs(ctx, domain.IAMID, queries) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/login_policy.go b/internal/api/grpc/admin/login_policy.go index 9d731ce78..e3b50cfda 100644 --- a/internal/api/grpc/admin/login_policy.go +++ b/internal/api/grpc/admin/login_policy.go @@ -35,18 +35,18 @@ func (s *Server) UpdateLoginPolicy(ctx context.Context, p *admin_pb.UpdateLoginP } func (s *Server) ListLoginPolicyIDPs(ctx context.Context, req *admin_pb.ListLoginPolicyIDPsRequest) (*admin_pb.ListLoginPolicyIDPsResponse, error) { - res, err := s.iam.SearchDefaultIDPProviders(ctx, ListLoginPolicyIDPsRequestToModel(req)) + res, err := s.query.IDPLoginPolicyLinks(ctx, domain.IAMID, ListLoginPolicyIDPsRequestToQuery(req)) if err != nil { return nil, err } return &admin_pb.ListLoginPolicyIDPsResponse{ - Result: idp.ExternalIDPViewsToLoginPolicyLinkPb(res.Result), - Details: object.ToListDetails(res.TotalResult, res.Sequence, res.Timestamp), + Result: idp.IDPLoginPolicyLinksToPb(res.Links), + Details: object.ToListDetails(res.Count, res.Sequence, res.Timestamp), }, nil } func (s *Server) AddIDPToLoginPolicy(ctx context.Context, req *admin_pb.AddIDPToLoginPolicyRequest) (*admin_pb.AddIDPToLoginPolicyResponse, error) { - idp, err := s.command.AddIDPProviderToDefaultLoginPolicy(ctx, &domain.IDPProvider{IDPConfigID: req.IdpId}) //TODO: old way was to also add type but this doesnt make sense in my point of view + idp, err := s.command.AddIDPProviderToDefaultLoginPolicy(ctx, &domain.IDPProvider{IDPConfigID: req.IdpId}) if err != nil { return nil, err } diff --git a/internal/api/grpc/admin/login_policy_converter.go b/internal/api/grpc/admin/login_policy_converter.go index b2af7a00e..900e88dbd 100644 --- a/internal/api/grpc/admin/login_policy_converter.go +++ b/internal/api/grpc/admin/login_policy_converter.go @@ -4,7 +4,7 @@ import ( "github.com/caos/zitadel/internal/api/grpc/object" policy_grpc "github.com/caos/zitadel/internal/api/grpc/policy" "github.com/caos/zitadel/internal/domain" - "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/query" admin_pb "github.com/caos/zitadel/pkg/grpc/admin" ) @@ -19,13 +19,13 @@ func updateLoginPolicyToDomain(p *admin_pb.UpdateLoginPolicyRequest) *domain.Log } } -func ListLoginPolicyIDPsRequestToModel(req *admin_pb.ListLoginPolicyIDPsRequest) *model.IDPProviderSearchRequest { +func ListLoginPolicyIDPsRequestToQuery(req *admin_pb.ListLoginPolicyIDPsRequest) *query.IDPLoginPolicyLinksSearchQuery { offset, limit, asc := object.ListQueryToModel(req.Query) - return &model.IDPProviderSearchRequest{ - Offset: offset, - Limit: limit, - Asc: asc, - // SortingColumn: model.IDPProviderSearchKey, //TODO: not in proto - // Queries: []*model.IDPProviderSearchQuery, //TODO: not in proto + return &query.IDPLoginPolicyLinksSearchQuery{ + SearchRequest: query.SearchRequest{ + Offset: offset, + Limit: limit, + Asc: asc, + }, } } diff --git a/internal/api/grpc/auth/idp.go b/internal/api/grpc/auth/idp.go index 5077a2b57..cf6e1d2f0 100644 --- a/internal/api/grpc/auth/idp.go +++ b/internal/api/grpc/auth/idp.go @@ -13,16 +13,16 @@ func (s *Server) ListMyLinkedIDPs(ctx context.Context, req *auth_pb.ListMyLinked if err != nil { return nil, err } - idps, err := s.query.UserIDPLinks(ctx, q) + links, err := s.query.IDPUserLinks(ctx, q) if err != nil { return nil, err } return &auth_pb.ListMyLinkedIDPsResponse{ - Result: idp_grpc.IDPUserLinksToPb(idps.Links), + Result: idp_grpc.IDPUserLinksToPb(links.Links), Details: object.ToListDetails( - idps.Count, - idps.Sequence, - idps.Timestamp, + links.Count, + links.Sequence, + links.Timestamp, ), }, nil } diff --git a/internal/api/grpc/auth/idp_converter.go b/internal/api/grpc/auth/idp_converter.go index c2ee6335c..08fe6efcd 100644 --- a/internal/api/grpc/auth/idp_converter.go +++ b/internal/api/grpc/auth/idp_converter.go @@ -10,13 +10,13 @@ import ( auth_pb "github.com/caos/zitadel/pkg/grpc/auth" ) -func ListMyLinkedIDPsRequestToQuery(ctx context.Context, req *auth_pb.ListMyLinkedIDPsRequest) (*query.UserIDPLinksSearchQuery, error) { +func ListMyLinkedIDPsRequestToQuery(ctx context.Context, req *auth_pb.ListMyLinkedIDPsRequest) (*query.IDPUserLinksSearchQuery, error) { offset, limit, asc := object.ListQueryToModel(req.Query) - q, err := query.NewUserIDPLinksUserIDSearchQuery(authz.GetCtxData(ctx).UserID) + q, err := query.NewIDPUserLinksUserIDSearchQuery(authz.GetCtxData(ctx).UserID) if err != nil { return nil, err } - return &query.UserIDPLinksSearchQuery{ + return &query.IDPUserLinksSearchQuery{ SearchRequest: query.SearchRequest{ Offset: offset, Limit: limit, diff --git a/internal/api/grpc/idp/converter.go b/internal/api/grpc/idp/converter.go index bf352d3d1..7d420b263 100644 --- a/internal/api/grpc/idp/converter.go +++ b/internal/api/grpc/idp/converter.go @@ -48,23 +48,23 @@ func IDPViewToPb(idp *query.IDP) *idp_pb.IDP { return mapped } -func ExternalIDPViewsToLoginPolicyLinkPb(links []*iam_model.IDPProviderView) []*idp_pb.IDPLoginPolicyLink { +func IDPLoginPolicyLinksToPb(links []*query.IDPLoginPolicyLink) []*idp_pb.IDPLoginPolicyLink { l := make([]*idp_pb.IDPLoginPolicyLink, len(links)) for i, link := range links { - l[i] = ExternalIDPViewToLoginPolicyLinkPb(link) + l[i] = IDPLoginPolicyLinkToPb(link) } return l } -func ExternalIDPViewToLoginPolicyLinkPb(link *iam_model.IDPProviderView) *idp_pb.IDPLoginPolicyLink { +func IDPLoginPolicyLinkToPb(link *query.IDPLoginPolicyLink) *idp_pb.IDPLoginPolicyLink { return &idp_pb.IDPLoginPolicyLink{ - IdpId: link.IDPConfigID, - IdpName: link.Name, - IdpType: IDPTypeViewToPb(link.IDPConfigType), + IdpId: link.IDPID, + IdpName: link.IDPName, + IdpType: IDPTypeToPb(link.IDPType), } } -func IDPUserLinksToPb(res []*query.UserIDPLink) []*idp_pb.IDPUserLink { +func IDPUserLinksToPb(res []*query.IDPUserLink) []*idp_pb.IDPUserLink { links := make([]*idp_pb.IDPUserLink, len(res)) for i, link := range res { links[i] = IDPUserLinkToPb(link) @@ -72,7 +72,7 @@ func IDPUserLinksToPb(res []*query.UserIDPLink) []*idp_pb.IDPUserLink { return links } -func IDPUserLinkToPb(link *query.UserIDPLink) *idp_pb.IDPUserLink { +func IDPUserLinkToPb(link *query.IDPUserLink) *idp_pb.IDPUserLink { return &idp_pb.IDPUserLink{ UserId: link.UserID, IdpId: link.IDPID, @@ -83,19 +83,6 @@ func IDPUserLinkToPb(link *query.UserIDPLink) *idp_pb.IDPUserLink { } } -func IDPTypeViewToPb(idpType iam_model.IdpConfigType) idp_pb.IDPType { - switch idpType { - case iam_model.IDPConfigTypeOIDC: - return idp_pb.IDPType_IDP_TYPE_OIDC - case iam_model.IDPConfigTypeSAML: - return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED - case iam_model.IDPConfigTypeJWT: - return idp_pb.IDPType_IDP_TYPE_JWT - default: - return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED - } -} - func IDPTypeToPb(idpType domain.IDPConfigType) idp_pb.IDPType { switch idpType { case domain.IDPConfigTypeOIDC: diff --git a/internal/api/grpc/management/idp.go b/internal/api/grpc/management/idp.go index a9415d3cd..5780d1943 100644 --- a/internal/api/grpc/management/idp.go +++ b/internal/api/grpc/management/idp.go @@ -31,6 +31,7 @@ func (s *Server) ListOrgIDPs(ctx context.Context, req *mgmt_pb.ListOrgIDPsReques Details: object_pb.ToListDetails(resp.Count, resp.Sequence, resp.Timestamp), }, nil } + func (s *Server) AddOrgOIDCIDP(ctx context.Context, req *mgmt_pb.AddOrgOIDCIDPRequest) (*mgmt_pb.AddOrgOIDCIDPResponse, error) { config, err := s.command.AddIDPConfig(ctx, addOIDCIDPRequestToDomain(req), authz.GetCtxData(ctx).OrgID) if err != nil { @@ -68,6 +69,7 @@ func (s *Server) DeactivateOrgIDP(ctx context.Context, req *mgmt_pb.DeactivateOr } return &mgmt_pb.DeactivateOrgIDPResponse{Details: object_pb.DomainToChangeDetailsPb(objectDetails)}, nil } + func (s *Server) ReactivateOrgIDP(ctx context.Context, req *mgmt_pb.ReactivateOrgIDPRequest) (*mgmt_pb.ReactivateOrgIDPResponse, error) { objectDetails, err := s.command.ReactivateIDPConfig(ctx, req.IdpId, authz.GetCtxData(ctx).OrgID) if err != nil { @@ -75,6 +77,7 @@ func (s *Server) ReactivateOrgIDP(ctx context.Context, req *mgmt_pb.ReactivateOr } return &mgmt_pb.ReactivateOrgIDPResponse{Details: object_pb.DomainToChangeDetailsPb(objectDetails)}, nil } + func (s *Server) RemoveOrgIDP(ctx context.Context, req *mgmt_pb.RemoveOrgIDPRequest) (*mgmt_pb.RemoveOrgIDPResponse, error) { idpProviders, err := s.org.GetIDPProvidersByIDPConfigID(ctx, authz.GetCtxData(ctx).OrgID, req.IdpId) if err != nil { @@ -90,6 +93,7 @@ func (s *Server) RemoveOrgIDP(ctx context.Context, req *mgmt_pb.RemoveOrgIDPRequ } return &mgmt_pb.RemoveOrgIDPResponse{}, nil } + func (s *Server) UpdateOrgIDP(ctx context.Context, req *mgmt_pb.UpdateOrgIDPRequest) (*mgmt_pb.UpdateOrgIDPResponse, error) { config, err := s.command.ChangeIDPConfig(ctx, updateIDPToDomain(req), authz.GetCtxData(ctx).OrgID) if err != nil { diff --git a/internal/api/grpc/management/policy_login.go b/internal/api/grpc/management/policy_login.go index 49dabf0bc..7b6260fc4 100644 --- a/internal/api/grpc/management/policy_login.go +++ b/internal/api/grpc/management/policy_login.go @@ -68,13 +68,13 @@ func (s *Server) ResetLoginPolicyToDefault(ctx context.Context, req *mgmt_pb.Res } func (s *Server) ListLoginPolicyIDPs(ctx context.Context, req *mgmt_pb.ListLoginPolicyIDPsRequest) (*mgmt_pb.ListLoginPolicyIDPsResponse, error) { - res, err := s.org.SearchIDPProviders(ctx, ListLoginPolicyIDPsRequestToModel(req)) + res, err := s.query.IDPLoginPolicyLinks(ctx, authz.GetCtxData(ctx).OrgID, ListLoginPolicyIDPsRequestToQuery(req)) if err != nil { return nil, err } return &mgmt_pb.ListLoginPolicyIDPsResponse{ - Result: idp.ExternalIDPViewsToLoginPolicyLinkPb(res.Result), - Details: object.ToListDetails(res.TotalResult, res.Sequence, res.Timestamp), + Result: idp.IDPLoginPolicyLinksToPb(res.Links), + Details: object.ToListDetails(res.Count, res.Sequence, res.Timestamp), }, nil } diff --git a/internal/api/grpc/management/policy_login_converter.go b/internal/api/grpc/management/policy_login_converter.go index a85d15e8b..706a0f941 100644 --- a/internal/api/grpc/management/policy_login_converter.go +++ b/internal/api/grpc/management/policy_login_converter.go @@ -4,7 +4,7 @@ import ( "github.com/caos/zitadel/internal/api/grpc/object" policy_grpc "github.com/caos/zitadel/internal/api/grpc/policy" "github.com/caos/zitadel/internal/domain" - "github.com/caos/zitadel/internal/iam/model" + "github.com/caos/zitadel/internal/query" mgmt_pb "github.com/caos/zitadel/pkg/grpc/management" ) @@ -30,13 +30,13 @@ func updateLoginPolicyToDomain(p *mgmt_pb.UpdateCustomLoginPolicyRequest) *domai } } -func ListLoginPolicyIDPsRequestToModel(req *mgmt_pb.ListLoginPolicyIDPsRequest) *model.IDPProviderSearchRequest { +func ListLoginPolicyIDPsRequestToQuery(req *mgmt_pb.ListLoginPolicyIDPsRequest) *query.IDPLoginPolicyLinksSearchQuery { offset, limit, asc := object.ListQueryToModel(req.Query) - return &model.IDPProviderSearchRequest{ - Offset: offset, - Limit: limit, - Asc: asc, - // SortingColumn: model.IDPProviderSearchKey, //TODO: not in proto - // Queries: []*model.IDPProviderSearchQuery, //TODO: not in proto + return &query.IDPLoginPolicyLinksSearchQuery{ + SearchRequest: query.SearchRequest{ + Offset: offset, + Limit: limit, + Asc: asc, + }, } } diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go index 5d052f3f4..516dc08ab 100644 --- a/internal/api/grpc/management/user.go +++ b/internal/api/grpc/management/user.go @@ -610,7 +610,7 @@ func (s *Server) ListHumanLinkedIDPs(ctx context.Context, req *mgmt_pb.ListHuman if err != nil { return nil, err } - res, err := s.query.UserIDPLinks(ctx, queries) + res, err := s.query.IDPUserLinks(ctx, queries) if err != nil { return nil, err } diff --git a/internal/api/grpc/management/user_converter.go b/internal/api/grpc/management/user_converter.go index 3b7b42b68..1f3f1b693 100644 --- a/internal/api/grpc/management/user_converter.go +++ b/internal/api/grpc/management/user_converter.go @@ -235,17 +235,17 @@ func RemoveHumanLinkedIDPRequestToDomain(ctx context.Context, req *mgmt_pb.Remov } } -func ListHumanLinkedIDPsRequestToQuery(ctx context.Context, req *mgmt_pb.ListHumanLinkedIDPsRequest) (*query.UserIDPLinksSearchQuery, error) { +func ListHumanLinkedIDPsRequestToQuery(ctx context.Context, req *mgmt_pb.ListHumanLinkedIDPsRequest) (*query.IDPUserLinksSearchQuery, error) { offset, limit, asc := object.ListQueryToModel(req.Query) - userQuery, err := query.NewUserIDPLinksUserIDSearchQuery(req.UserId) + userQuery, err := query.NewIDPUserLinksUserIDSearchQuery(req.UserId) if err != nil { return nil, err } - resourceOwnerQuery, err := query.NewUserIDPLinksResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID) + resourceOwnerQuery, err := query.NewIDPUserLinksResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } - return &query.UserIDPLinksSearchQuery{ + return &query.IDPUserLinksSearchQuery{ SearchRequest: query.SearchRequest{ Offset: offset, Limit: limit, diff --git a/internal/query/idp_login_policy_link.go b/internal/query/idp_login_policy_link.go new file mode 100644 index 000000000..2172bbf4e --- /dev/null +++ b/internal/query/idp_login_policy_link.go @@ -0,0 +1,135 @@ +package query + +import ( + "context" + "database/sql" + + sq "github.com/Masterminds/squirrel" + "github.com/caos/zitadel/internal/domain" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/query/projection" +) + +type IDPLoginPolicyLink struct { + IDPID string + IDPName string + IDPType domain.IDPConfigType +} + +type IDPLoginPolicyLinks struct { + SearchResponse + Links []*IDPLoginPolicyLink +} + +type IDPLoginPolicyLinksSearchQuery struct { + SearchRequest + Queries []SearchQuery +} + +func (q *IDPLoginPolicyLinksSearchQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { + query = q.SearchRequest.toQuery(query) + for _, q := range q.Queries { + query = q.toQuery(query) + } + return query +} + +var ( + idpLoginPolicyLinkTable = table{ + name: projection.IDPLoginPolicyLinkTable, + } + IDPLoginPolicyLinkIDPIDCol = Column{ + name: projection.IDPLoginPolicyLinkIDPIDCol, + table: idpLoginPolicyLinkTable, + } + IDPLoginPolicyLinkCreationDateCol = Column{ + name: projection.IDPLoginPolicyLinkCreationDateCol, + table: idpLoginPolicyLinkTable, + } + IDPLoginPolicyLinkChangeDateCol = Column{ + name: projection.IDPLoginPolicyLinkChangeDateCol, + table: idpLoginPolicyLinkTable, + } + IDPLoginPolicyLinkSequenceCol = Column{ + name: projection.IDPLoginPolicyLinkSequenceCol, + table: idpLoginPolicyLinkTable, + } + IDPLoginPolicyLinkResourceOwnerCol = Column{ + name: projection.IDPLoginPolicyLinkResourceOwnerCol, + table: idpLoginPolicyLinkTable, + } + IDPLoginPolicyLinkProviderTypeCol = Column{ + name: projection.IDPLoginPolicyLinkProviderTypeCol, + table: idpLoginPolicyLinkTable, + } +) + +func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, queries *IDPLoginPolicyLinksSearchQuery) (idps *IDPLoginPolicyLinks, err error) { + query, scan := prepareIDPLoginPolicyLinksQuery() + stmt, args, err := queries.toQuery(query).Where( + sq.Eq{IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner}, + ).ToSql() + if err != nil { + return nil, errors.ThrowInvalidArgument(err, "QUERY-FDbKW", "Errors.Query.InvalidRequest") + } + + rows, err := q.client.QueryContext(ctx, stmt, args...) + if err != nil { + return nil, errors.ThrowInternal(err, "QUERY-ZkKUc", "Errors.Internal") + } + idps, err = scan(rows) + if err != nil { + return nil, err + } + idps.LatestSequence, err = q.latestSequence(ctx, idpLoginPolicyLinkTable) + return idps, err +} + +func prepareIDPLoginPolicyLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) { + return sq.Select( + IDPLoginPolicyLinkIDPIDCol.identifier(), + IDPNameCol.identifier(), + IDPTypeCol.identifier(), + countColumn.identifier()). + From(idpLoginPolicyLinkTable.identifier()). + LeftJoin(join(IDPIDCol, IDPLoginPolicyLinkIDPIDCol)).PlaceholderFormat(sq.Dollar), + func(rows *sql.Rows) (*IDPLoginPolicyLinks, error) { + links := make([]*IDPLoginPolicyLink, 0) + var count uint64 + for rows.Next() { + var ( + idpName = sql.NullString{} + idpType = sql.NullInt16{} + link = new(IDPLoginPolicyLink) + ) + err := rows.Scan( + &link.IDPID, + &idpName, + &idpType, + &count, + ) + if err != nil { + return nil, err + } + 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 err := rows.Close(); err != nil { + return nil, errors.ThrowInternal(err, "QUERY-vOLFG", "Errors.Query.CloseRows") + } + + return &IDPLoginPolicyLinks{ + Links: links, + SearchResponse: SearchResponse{ + Count: count, + }, + }, nil + } +} diff --git a/internal/query/idp_login_policy_link_test.go b/internal/query/idp_login_policy_link_test.go new file mode 100644 index 000000000..0a053c1dc --- /dev/null +++ b/internal/query/idp_login_policy_link_test.go @@ -0,0 +1,121 @@ +package query + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "regexp" + "testing" + + "github.com/caos/zitadel/internal/domain" +) + +var ( + loginPolicyIDPLinksQuery = regexp.QuoteMeta(`SELECT zitadel.projections.idp_login_policy_links.idp_id,` + + ` zitadel.projections.idps.name,` + + ` zitadel.projections.idps.type,` + + ` COUNT(*) OVER ()` + + ` FROM zitadel.projections.idp_login_policy_links` + + ` LEFT JOIN zitadel.projections.idps ON zitadel.projections.idp_login_policy_links.idp_id = zitadel.projections.idps.id`) + loginPolicyIDPLinksCols = []string{ + "idp_id", + "name", + "type", + "count", + } +) + +func Test_IDPLoginPolicyLinkPrepares(t *testing.T) { + type want struct { + sqlExpectations sqlExpectation + err checkErr + } + tests := []struct { + name string + prepare interface{} + want want + object interface{} + }{ + { + name: "prepareIDPsQuery found", + prepare: prepareIDPLoginPolicyLinksQuery, + want: want{ + sqlExpectations: mockQueries( + loginPolicyIDPLinksQuery, + loginPolicyIDPLinksCols, + [][]driver.Value{ + { + "idp-id", + "idp-name", + domain.IDPConfigTypeJWT, + }, + }, + ), + }, + object: &IDPLoginPolicyLinks{ + SearchResponse: SearchResponse{ + Count: 1, + }, + Links: []*IDPLoginPolicyLink{ + { + IDPID: "idp-id", + IDPName: "idp-name", + IDPType: domain.IDPConfigTypeJWT, + }, + }, + }, + }, + { + name: "prepareIDPsQuery no idp", + prepare: prepareIDPLoginPolicyLinksQuery, + want: want{ + sqlExpectations: mockQueries( + loginPolicyIDPLinksQuery, + loginPolicyIDPLinksCols, + [][]driver.Value{ + { + "idp-id", + nil, + nil, + }, + }, + ), + }, + object: &IDPLoginPolicyLinks{ + SearchResponse: SearchResponse{ + Count: 1, + }, + Links: []*IDPLoginPolicyLink{ + { + IDPID: "idp-id", + IDPName: "", + IDPType: domain.IDPConfigTypeUnspecified, + }, + }, + }, + }, + { + name: "prepareIDPsQuery sql err", + prepare: prepareIDPLoginPolicyLinksQuery, + want: want{ + sqlExpectations: mockQueryErr( + loginPolicyIDPLinksQuery, + sql.ErrConnDone, + ), + err: func(err error) (error, bool) { + if !errors.Is(err, sql.ErrConnDone) { + return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false + } + return nil, true + }, + }, + object: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err) + }) + } +} diff --git a/internal/query/user_idp_link.go b/internal/query/idp_user_link.go similarity index 82% rename from internal/query/user_idp_link.go rename to internal/query/idp_user_link.go index a3a670244..633b2c708 100644 --- a/internal/query/user_idp_link.go +++ b/internal/query/idp_user_link.go @@ -10,7 +10,7 @@ import ( "github.com/caos/zitadel/internal/query/projection" ) -type UserIDPLink struct { +type IDPUserLink struct { IDPID string UserID string IDPName string @@ -19,17 +19,17 @@ type UserIDPLink struct { IDPType domain.IDPConfigType } -type UserIDPLinks struct { +type IDPUserLinks struct { SearchResponse - Links []*UserIDPLink + Links []*IDPUserLink } -type UserIDPLinksSearchQuery struct { +type IDPUserLinksSearchQuery struct { SearchRequest Queries []SearchQuery } -func (q *UserIDPLinksSearchQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { +func (q *IDPUserLinksSearchQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder { query = q.SearchRequest.toQuery(query) for _, q := range q.Queries { query = q.toQuery(query) @@ -75,8 +75,8 @@ var ( } ) -func (q *Queries) UserIDPLinks(ctx context.Context, queries *UserIDPLinksSearchQuery) (idps *UserIDPLinks, err error) { - query, scan := prepareUserIDPLinksQuery() +func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery) (idps *IDPUserLinks, err error) { + query, scan := prepareIDPUserLinksQuery() stmt, args, err := queries.toQuery(query).ToSql() if err != nil { return nil, errors.ThrowInvalidArgument(err, "QUERY-4zzFK", "Errors.Query.InvalidRequest") @@ -94,15 +94,15 @@ func (q *Queries) UserIDPLinks(ctx context.Context, queries *UserIDPLinksSearchQ return idps, err } -func NewUserIDPLinksUserIDSearchQuery(value string) (SearchQuery, error) { +func NewIDPUserLinksUserIDSearchQuery(value string) (SearchQuery, error) { return NewTextQuery(IDPUserLinkUserIDCol, value, TextEquals) } -func NewUserIDPLinksResourceOwnerSearchQuery(value string) (SearchQuery, error) { +func NewIDPUserLinksResourceOwnerSearchQuery(value string) (SearchQuery, error) { return NewTextQuery(IDPUserLinkResourceOwnerCol, value, TextEquals) } -func prepareUserIDPLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserIDPLinks, error)) { +func prepareIDPUserLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPUserLinks, error)) { return sq.Select( IDPUserLinkIDPIDCol.identifier(), IDPUserLinkUserIDCol.identifier(), @@ -113,14 +113,14 @@ func prepareUserIDPLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserIDPLink countColumn.identifier()). From(idpUserLinkTable.identifier()). LeftJoin(join(IDPIDCol, IDPUserLinkIDPIDCol)).PlaceholderFormat(sq.Dollar), - func(rows *sql.Rows) (*UserIDPLinks, error) { - idps := make([]*UserIDPLink, 0) + func(rows *sql.Rows) (*IDPUserLinks, error) { + idps := make([]*IDPUserLink, 0) var count uint64 for rows.Next() { var ( idpName = sql.NullString{} idpType = sql.NullInt16{} - idp = new(UserIDPLink) + idp = new(IDPUserLink) ) err := rows.Scan( &idp.IDPID, @@ -148,7 +148,7 @@ func prepareUserIDPLinksQuery() (sq.SelectBuilder, func(*sql.Rows) (*UserIDPLink return nil, errors.ThrowInternal(err, "QUERY-nwx6U", "Errors.Query.CloseRows") } - return &UserIDPLinks{ + return &IDPUserLinks{ Links: idps, SearchResponse: SearchResponse{ Count: count, diff --git a/internal/query/user_idp_link_test.go b/internal/query/idp_user_link_test.go similarity index 84% rename from internal/query/user_idp_link_test.go rename to internal/query/idp_user_link_test.go index e63e2f361..b8137506c 100644 --- a/internal/query/user_idp_link_test.go +++ b/internal/query/idp_user_link_test.go @@ -12,7 +12,7 @@ import ( ) var ( - userIDPLinksQuery = regexp.QuoteMeta(`SELECT zitadel.projections.idp_user_links.idp_id,` + + idpUserLinksQuery = regexp.QuoteMeta(`SELECT zitadel.projections.idp_user_links.idp_id,` + ` zitadel.projections.idp_user_links.user_id,` + ` zitadel.projections.idps.name,` + ` zitadel.projections.idp_user_links.external_user_id,` + @@ -21,7 +21,7 @@ var ( ` COUNT(*) OVER ()` + ` FROM zitadel.projections.idp_user_links` + ` LEFT JOIN zitadel.projections.idps ON zitadel.projections.idp_user_links.idp_id = zitadel.projections.idps.id`) - userIDPLinksCols = []string{ + idpUserLinksCols = []string{ "idp_id", "user_id", "name", @@ -32,7 +32,7 @@ var ( } ) -func Test_UserIDPLinkPrepares(t *testing.T) { +func Test_IDPUserLinkPrepares(t *testing.T) { type want struct { sqlExpectations sqlExpectation err checkErr @@ -45,11 +45,11 @@ func Test_UserIDPLinkPrepares(t *testing.T) { }{ { name: "prepareIDPsQuery found", - prepare: prepareUserIDPLinksQuery, + prepare: prepareIDPUserLinksQuery, want: want{ sqlExpectations: mockQueries( - userIDPLinksQuery, - userIDPLinksCols, + idpUserLinksQuery, + idpUserLinksCols, [][]driver.Value{ { "idp-id", @@ -62,11 +62,11 @@ func Test_UserIDPLinkPrepares(t *testing.T) { }, ), }, - object: &UserIDPLinks{ + object: &IDPUserLinks{ SearchResponse: SearchResponse{ Count: 1, }, - Links: []*UserIDPLink{ + Links: []*IDPUserLink{ { IDPID: "idp-id", UserID: "user-id", @@ -80,11 +80,11 @@ func Test_UserIDPLinkPrepares(t *testing.T) { }, { name: "prepareIDPsQuery no idp", - prepare: prepareUserIDPLinksQuery, + prepare: prepareIDPUserLinksQuery, want: want{ sqlExpectations: mockQueries( - userIDPLinksQuery, - userIDPLinksCols, + idpUserLinksQuery, + idpUserLinksCols, [][]driver.Value{ { "idp-id", @@ -97,11 +97,11 @@ func Test_UserIDPLinkPrepares(t *testing.T) { }, ), }, - object: &UserIDPLinks{ + object: &IDPUserLinks{ SearchResponse: SearchResponse{ Count: 1, }, - Links: []*UserIDPLink{ + Links: []*IDPUserLink{ { IDPID: "idp-id", UserID: "user-id", @@ -115,10 +115,10 @@ func Test_UserIDPLinkPrepares(t *testing.T) { }, { name: "prepareIDPsQuery sql err", - prepare: prepareUserIDPLinksQuery, + prepare: prepareIDPUserLinksQuery, want: want{ sqlExpectations: mockQueryErr( - userIDPLinksQuery, + idpUserLinksQuery, sql.ErrConnDone, ), err: func(err error) (error, bool) {