zitadel/internal/api/grpc/management/user_converter.go
Silvan c9face4ea4
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
2021-12-08 14:49:19 +01:00

312 lines
9.7 KiB
Go

package management
import (
"context"
"time"
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/grpc/authn"
"github.com/caos/zitadel/internal/api/grpc/metadata"
"github.com/caos/zitadel/internal/api/grpc/object"
user_grpc "github.com/caos/zitadel/internal/api/grpc/user"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore/v1/models"
key_model "github.com/caos/zitadel/internal/key/model"
"github.com/caos/zitadel/internal/query"
user_model "github.com/caos/zitadel/internal/user/model"
mgmt_pb "github.com/caos/zitadel/pkg/grpc/management"
user_pb "github.com/caos/zitadel/pkg/grpc/user"
)
func ListUsersRequestToModel(ctx context.Context, req *mgmt_pb.ListUsersRequest) *user_model.UserSearchRequest {
offset, limit, asc := object.ListQueryToModel(req.Query)
req.Queries = append(req.Queries, &user_pb.SearchQuery{
Query: &user_pb.SearchQuery_ResourceOwner{
ResourceOwner: &user_pb.ResourceOwnerQuery{
OrgID: authz.GetCtxData(ctx).OrgID,
},
},
})
return &user_model.UserSearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
Queries: user_grpc.UserQueriesToModel(req.Queries),
}
}
func BulkSetMetadataToDomain(req *mgmt_pb.BulkSetUserMetadataRequest) []*domain.Metadata {
metadata := make([]*domain.Metadata, len(req.Metadata))
for i, data := range req.Metadata {
metadata[i] = &domain.Metadata{
Key: data.Key,
Value: data.Value,
}
}
return metadata
}
func ListUserMetadataToDomain(req *mgmt_pb.ListUserMetadataRequest) *domain.MetadataSearchRequest {
offset, limit, asc := object.ListQueryToModel(req.Query)
return &domain.MetadataSearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
Queries: metadata.MetadataQueriesToModel(req.Queries),
}
}
func AddHumanUserRequestToDomain(req *mgmt_pb.AddHumanUserRequest) *domain.Human {
h := &domain.Human{
Username: req.UserName,
}
preferredLanguage, err := language.Parse(req.Profile.PreferredLanguage)
logging.Log("MANAG-M029f").OnError(err).Debug("language malformed")
h.Profile = &domain.Profile{
FirstName: req.Profile.FirstName,
LastName: req.Profile.LastName,
NickName: req.Profile.NickName,
DisplayName: req.Profile.DisplayName,
PreferredLanguage: preferredLanguage,
Gender: user_grpc.GenderToDomain(req.Profile.Gender),
}
h.Email = &domain.Email{
EmailAddress: req.Email.Email,
IsEmailVerified: req.Email.IsEmailVerified,
}
if req.Phone != nil {
h.Phone = &domain.Phone{
PhoneNumber: req.Phone.Phone,
IsPhoneVerified: req.Phone.IsPhoneVerified,
}
}
if req.InitialPassword != "" {
h.Password = &domain.Password{SecretString: req.InitialPassword, ChangeRequired: true}
}
return h
}
func ImportHumanUserRequestToDomain(req *mgmt_pb.ImportHumanUserRequest) (human *domain.Human, passwordless bool) {
human = &domain.Human{
Username: req.UserName,
}
preferredLanguage, err := language.Parse(req.Profile.PreferredLanguage)
logging.Log("MANAG-3GUFJ").OnError(err).Debug("language malformed")
human.Profile = &domain.Profile{
FirstName: req.Profile.FirstName,
LastName: req.Profile.LastName,
NickName: req.Profile.NickName,
DisplayName: req.Profile.DisplayName,
PreferredLanguage: preferredLanguage,
Gender: user_grpc.GenderToDomain(req.Profile.Gender),
}
human.Email = &domain.Email{
EmailAddress: req.Email.Email,
IsEmailVerified: req.Email.IsEmailVerified,
}
if req.Phone != nil {
human.Phone = &domain.Phone{
PhoneNumber: req.Phone.Phone,
IsPhoneVerified: req.Phone.IsPhoneVerified,
}
}
if req.Password != "" {
human.Password = &domain.Password{SecretString: req.Password}
human.Password.ChangeRequired = req.PasswordChangeRequired
}
return human, req.RequestPasswordlessRegistration
}
func AddMachineUserRequestToDomain(req *mgmt_pb.AddMachineUserRequest) *domain.Machine {
return &domain.Machine{
Username: req.UserName,
Name: req.Name,
Description: req.Description,
}
}
func UpdateHumanProfileRequestToDomain(req *mgmt_pb.UpdateHumanProfileRequest) *domain.Profile {
preferredLanguage, err := language.Parse(req.PreferredLanguage)
logging.Log("MANAG-GPcYv").OnError(err).Debug("language malformed")
return &domain.Profile{
ObjectRoot: models.ObjectRoot{AggregateID: req.UserId},
FirstName: req.FirstName,
LastName: req.LastName,
NickName: req.NickName,
DisplayName: req.DisplayName,
PreferredLanguage: preferredLanguage,
Gender: user_grpc.GenderToDomain(req.Gender),
}
}
func UpdateHumanEmailRequestToDomain(ctx context.Context, req *mgmt_pb.UpdateHumanEmailRequest) *domain.Email {
return &domain.Email{
ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId,
ResourceOwner: authz.GetCtxData(ctx).OrgID,
},
EmailAddress: req.Email,
IsEmailVerified: req.IsEmailVerified,
}
}
func UpdateHumanPhoneRequestToDomain(req *mgmt_pb.UpdateHumanPhoneRequest) *domain.Phone {
return &domain.Phone{
ObjectRoot: models.ObjectRoot{AggregateID: req.UserId},
PhoneNumber: req.Phone,
IsPhoneVerified: req.IsPhoneVerified,
}
}
func notifyTypeToDomain(state mgmt_pb.SendHumanResetPasswordNotificationRequest_Type) domain.NotificationType {
switch state {
case mgmt_pb.SendHumanResetPasswordNotificationRequest_TYPE_EMAIL:
return domain.NotificationTypeEmail
case mgmt_pb.SendHumanResetPasswordNotificationRequest_TYPE_SMS:
return domain.NotificationTypeSms
default:
return domain.NotificationTypeEmail
}
}
func UpdateMachineRequestToDomain(ctx context.Context, req *mgmt_pb.UpdateMachineRequest) *domain.Machine {
return &domain.Machine{
ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId,
ResourceOwner: authz.GetCtxData(ctx).OrgID,
},
Name: req.Name,
Description: req.Description,
}
}
func ListMachineKeysRequestToModel(req *mgmt_pb.ListMachineKeysRequest) *key_model.AuthNKeySearchRequest {
offset, limit, asc := object.ListQueryToModel(req.Query)
return &key_model.AuthNKeySearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
Queries: []*key_model.AuthNKeySearchQuery{
{
Key: key_model.AuthNKeyObjectType,
Method: domain.SearchMethodEquals,
Value: key_model.AuthNKeyObjectTypeUser,
}, {
Key: key_model.AuthNKeyObjectID,
Method: domain.SearchMethodEquals,
Value: req.UserId,
},
},
}
}
func AddMachineKeyRequestToDomain(req *mgmt_pb.AddMachineKeyRequest) *domain.MachineKey {
expDate := time.Time{}
if req.ExpirationDate != nil {
var err error
expDate, err = ptypes.Timestamp(req.ExpirationDate)
logging.Log("MANAG-iNshR").OnError(err).Debug("unable to parse expiration date")
}
return &domain.MachineKey{
ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId,
},
ExpirationDate: expDate,
Type: authn.KeyTypeToDomain(req.Type),
}
}
func RemoveHumanLinkedIDPRequestToDomain(ctx context.Context, req *mgmt_pb.RemoveHumanLinkedIDPRequest) *domain.UserIDPLink {
return &domain.UserIDPLink{
ObjectRoot: models.ObjectRoot{
AggregateID: req.UserId,
ResourceOwner: authz.GetCtxData(ctx).OrgID,
},
IDPConfigID: req.IdpId,
ExternalUserID: req.LinkedUserId,
}
}
func ListHumanLinkedIDPsRequestToQuery(ctx context.Context, req *mgmt_pb.ListHumanLinkedIDPsRequest) (*query.IDPUserLinksSearchQuery, error) {
offset, limit, asc := object.ListQueryToModel(req.Query)
userQuery, err := query.NewIDPUserLinksUserIDSearchQuery(req.UserId)
if err != nil {
return nil, err
}
resourceOwnerQuery, err := query.NewIDPUserLinksResourceOwnerSearchQuery(authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &query.IDPUserLinksSearchQuery{
SearchRequest: query.SearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
},
Queries: []query.SearchQuery{userQuery, resourceOwnerQuery},
}, nil
}
func ListUserMembershipsRequestToModel(req *mgmt_pb.ListUserMembershipsRequest) (*user_model.UserMembershipSearchRequest, error) {
offset, limit, asc := object.ListQueryToModel(req.Query)
queries, err := user_grpc.MembershipQueriesToModel(req.Queries)
if err != nil {
return nil, err
}
queries = append(queries, &user_model.UserMembershipSearchQuery{
Key: user_model.UserMembershipSearchKeyUserID,
Method: domain.SearchMethodEquals,
Value: req.UserId,
})
return &user_model.UserMembershipSearchRequest{
Offset: offset,
Limit: limit,
Asc: asc,
//SortingColumn: //TODO: sorting
Queries: queries,
}, nil
}
func UserMembershipViewsToDomain(memberships []*user_model.UserMembershipView) []*domain.UserMembership {
result := make([]*domain.UserMembership, len(memberships))
for i, membership := range memberships {
result[i] = &domain.UserMembership{
UserID: membership.UserID,
MemberType: MemberTypeToDomain(membership.MemberType),
AggregateID: membership.AggregateID,
ObjectID: membership.ObjectID,
Roles: membership.Roles,
DisplayName: membership.DisplayName,
CreationDate: membership.CreationDate,
ChangeDate: membership.ChangeDate,
ResourceOwner: membership.ResourceOwner,
ResourceOwnerName: membership.ResourceOwnerName,
Sequence: membership.Sequence,
}
}
return result
}
func MemberTypeToDomain(mType user_model.MemberType) domain.MemberType {
switch mType {
case user_model.MemberTypeIam:
return domain.MemberTypeIam
case user_model.MemberTypeOrganisation:
return domain.MemberTypeOrganisation
case user_model.MemberTypeProject:
return domain.MemberTypeProject
case user_model.MemberTypeProjectGrant:
return domain.MemberTypeProjectGrant
default:
return domain.MemberTypeUnspecified
}
}