feat: Import user and hide loginname suffix (#1464)

* fix: import user

* fix: label policy

* fix: label policy

* fix: label policy

* fix: migrations

* fix: migrations

* fix: migrations

* fix: label policy

* loginSuffix in login ui

* suffix

* fix cursor on disabled user selection

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2021-03-25 10:50:32 +01:00 committed by GitHub
parent a012aed5cb
commit 03ddb8fc38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 718 additions and 115 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/logging"
admin_model "github.com/caos/zitadel/internal/admin/model"
admin_view "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/config/systemdefaults"
@ -58,7 +59,7 @@ func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg)
if err != nil {
return nil, err
}
user, userAggregates, err := repo.UserEventstore.PrepareCreateUser(ctx, setUp.User, pwPolicyView, orgPolicy, org.AggregateID)
user, userAggregates, err := repo.UserEventstore.PrepareCreateUser(ctx, setUp.User, pwPolicyView, orgPolicy, true, org.AggregateID)
if err != nil {
return nil, err
}

View File

@ -9,8 +9,9 @@ import (
func labelPolicyToModel(policy *admin.DefaultLabelPolicyUpdate) *iam_model.LabelPolicy {
return &iam_model.LabelPolicy{
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
}
}
@ -22,10 +23,11 @@ func labelPolicyFromModel(policy *iam_model.LabelPolicy) *admin.DefaultLabelPoli
logging.Log("ADMIN-mAgcI").OnError(err).Debug("date parse failed")
return &admin.DefaultLabelPolicy{
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
CreationDate: creationDate,
ChangeDate: changeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
CreationDate: creationDate,
ChangeDate: changeDate,
}
}
@ -37,9 +39,10 @@ func labelPolicyViewFromModel(policy *iam_model.LabelPolicyView) *admin.DefaultL
logging.Log("ADMIN-Vhvfp").OnError(err).Debug("date parse failed")
return &admin.DefaultLabelPolicyView{
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
CreationDate: creationDate,
ChangeDate: changeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
CreationDate: creationDate,
ChangeDate: changeDate,
}
}

View File

@ -0,0 +1,45 @@
package management
import (
"context"
"github.com/caos/zitadel/pkg/grpc/management"
"github.com/golang/protobuf/ptypes/empty"
)
func (s *Server) GetLabelPolicy(ctx context.Context, _ *empty.Empty) (*management.LabelPolicyView, error) {
result, err := s.org.GetLabelPolicy(ctx)
if err != nil {
return nil, err
}
return labelPolicyViewFromModel(result), nil
}
func (s *Server) GetDefaultLabelPolicy(ctx context.Context, _ *empty.Empty) (*management.LabelPolicyView, error) {
result, err := s.org.GetLabelPolicy(ctx)
if err != nil {
return nil, err
}
return labelPolicyViewFromModel(result), nil
}
func (s *Server) CreateLabelPolicy(ctx context.Context, policy *management.LabelPolicyRequest) (*management.LabelPolicy, error) {
result, err := s.org.AddLabelPolicy(ctx, labelPolicyRequestToModel(policy))
if err != nil {
return nil, err
}
return labelPolicyFromModel(result), nil
}
func (s *Server) UpdateLabelPolicy(ctx context.Context, policy *management.LabelPolicyRequest) (*management.LabelPolicy, error) {
result, err := s.org.ChangeLabelPolicy(ctx, labelPolicyRequestToModel(policy))
if err != nil {
return nil, err
}
return labelPolicyFromModel(result), nil
}
func (s *Server) RemoveLabelPolicy(ctx context.Context, _ *empty.Empty) (*empty.Empty, error) {
err := s.org.RemoveLabelPolicy(ctx)
return &empty.Empty{}, err
}

View File

@ -0,0 +1,50 @@
package management
import (
"github.com/caos/logging"
"github.com/golang/protobuf/ptypes"
iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/pkg/grpc/management"
)
func labelPolicyRequestToModel(policy *management.LabelPolicyRequest) *iam_model.LabelPolicy {
return &iam_model.LabelPolicy{
SecondaryColor: policy.SecondaryColor,
PrimaryColor: policy.PrimaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
}
}
func labelPolicyFromModel(policy *iam_model.LabelPolicy) *management.LabelPolicy {
creationDate, err := ptypes.TimestampProto(policy.CreationDate)
logging.Log("GRPC-2Fsm8").OnError(err).Debug("date parse failed")
changeDate, err := ptypes.TimestampProto(policy.ChangeDate)
logging.Log("GRPC-3Flo0").OnError(err).Debug("date parse failed")
return &management.LabelPolicy{
SecondaryColor: policy.SecondaryColor,
PrimaryColor: policy.PrimaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
CreationDate: creationDate,
ChangeDate: changeDate,
}
}
func labelPolicyViewFromModel(policy *iam_model.LabelPolicyView) *management.LabelPolicyView {
creationDate, err := ptypes.TimestampProto(policy.CreationDate)
logging.Log("GRPC-5Tsm8").OnError(err).Debug("date parse failed")
changeDate, err := ptypes.TimestampProto(policy.ChangeDate)
logging.Log("GRPC-8dJgs").OnError(err).Debug("date parse failed")
return &management.LabelPolicyView{
Default: policy.Default,
SecondaryColor: policy.SecondaryColor,
PrimaryColor: policy.PrimaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
CreationDate: creationDate,
ChangeDate: changeDate,
}
}

View File

@ -59,6 +59,14 @@ func (s *Server) CreateUser(ctx context.Context, in *management.CreateUserReques
return userFromModel(user), nil
}
func (s *Server) ImportHuman(ctx context.Context, in *management.ImportHumanRequest) (*management.UserResponse, error) {
user, err := s.user.ImportUser(ctx, humanImportToModel(in), in.PasswordChangeRequired)
if err != nil {
return nil, err
}
return userFromModel(user), nil
}
func (s *Server) DeactivateUser(ctx context.Context, in *management.UserID) (*management.UserResponse, error) {
user, err := s.user.DeactivateUser(ctx, in.Id)
if err != nil {

View File

@ -60,6 +60,42 @@ func userCreateToModel(user *management.CreateUserRequest) *usr_model.User {
}
}
func humanImportToModel(user *management.ImportHumanRequest) *usr_model.User {
preferredLanguage, err := language.Parse(user.PreferredLanguage)
logging.Log("GRPC-cK5k2").OnError(err).Debug("language malformed")
human := &usr_model.Human{
Profile: &usr_model.Profile{
FirstName: user.FirstName,
LastName: user.LastName,
NickName: user.NickName,
PreferredLanguage: preferredLanguage,
Gender: genderToModel(user.Gender),
},
Email: &usr_model.Email{
EmailAddress: user.Email,
IsEmailVerified: user.IsEmailVerified,
},
Address: &usr_model.Address{
Country: user.Country,
Locality: user.Locality,
PostalCode: user.PostalCode,
Region: user.Region,
StreetAddress: user.StreetAddress,
},
}
if user.Password != "" {
human.Password = &usr_model.Password{SecretString: user.Password}
}
if user.Phone != "" {
human.Phone = &usr_model.Phone{PhoneNumber: user.Phone, IsPhoneVerified: user.IsPhoneVerified}
}
return &usr_model.User{
UserName: user.UserName,
Human: human,
}
}
func passwordRequestToModel(r *management.PasswordRequest) *usr_model.Password {
return &usr_model.Password{
ObjectRoot: models.ObjectRoot{AggregateID: r.Id},

View File

@ -244,7 +244,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
if request.RequestedOrgID != "" && request.RequestedOrgID != user.ResourceOwner {
return errors.ThrowPreconditionFailed(nil, "EVENT-fJe2a", "Errors.User.NotAllowedOrg")
}
request.SetUserInfo(user.ID, user.PreferredLoginName, user.DisplayName, user.ResourceOwner)
request.SetUserInfo(user.ID, user.UserName, user.PreferredLoginName, user.DisplayName, user.ResourceOwner)
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
}
@ -456,21 +456,30 @@ func (repo *AuthRequestRepo) fillLoginPolicy(ctx context.Context, request *model
orgID = repo.IAMID
}
policy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, orgID)
loginPolicy, idpProviders, err := repo.getLoginPolicyAndIDPProviders(ctx, orgID)
if err != nil {
return err
}
request.LoginPolicy = policy
request.LoginPolicy = loginPolicy
if idpProviders != nil {
request.AllowedExternalIDPs = idpProviders
}
labelPolicy, err := repo.getLabelPolicy(ctx, orgID)
if err != nil {
return err
}
request.LabelPolicy = labelPolicy
return nil
}
func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.AuthRequest, loginName string) (err error) {
user := new(user_view_model.UserView)
if request.RequestedOrgID != "" {
user, err = repo.View.UserByLoginNameAndResourceOwner(loginName, request.RequestedOrgID)
preferredLoginName := loginName
if request.RequestedOrgID != "" {
preferredLoginName += "@" + request.RequestedPrimaryDomain
}
user, err = repo.View.UserByLoginNameAndResourceOwner(preferredLoginName, request.RequestedOrgID)
} else {
user, err = repo.View.UserByLoginName(loginName)
if err == nil {
@ -484,7 +493,7 @@ func (repo *AuthRequestRepo) checkLoginName(ctx context.Context, request *model.
return err
}
request.SetUserInfo(user.ID, loginName, "", user.ResourceOwner)
request.SetUserInfo(user.ID, loginName, user.PreferredLoginName, "", user.ResourceOwner)
return nil
}
@ -527,7 +536,7 @@ func (repo *AuthRequestRepo) checkExternalUserLogin(request *model.AuthRequest,
if err != nil {
return err
}
request.SetUserInfo(externalIDP.UserID, "", "", externalIDP.ResourceOwner)
request.SetUserInfo(externalIDP.UserID, "", "", "", externalIDP.ResourceOwner)
return nil
}
@ -630,6 +639,7 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
users[i] = model.UserSelection{
UserID: session.UserID,
DisplayName: session.DisplayName,
UserName: session.UserName,
LoginName: session.LoginName,
UserSessionState: session.State,
SelectionPossible: request.RequestedOrgID == "" || request.RequestedOrgID == session.ResourceOwner,
@ -733,6 +743,21 @@ func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (
return iam_es_model.LoginPolicyViewToModel(policy), err
}
func (repo *AuthRequestRepo) getLabelPolicy(ctx context.Context, orgID string) (*iam_model.LabelPolicyView, error) {
policy, err := repo.View.LabelPolicyByAggregateID(orgID)
if errors.IsNotFound(err) {
policy, err = repo.View.LabelPolicyByAggregateID(repo.IAMID)
if err != nil {
return nil, err
}
policy.Default = true
}
if err != nil {
return nil, err
}
return iam_es_model.LabelPolicyViewToModel(policy), err
}
func setOrgID(orgViewProvider orgViewProvider, request *model.AuthRequest) error {
primaryDomain := request.GetScopeOrgPrimaryDomain()
if primaryDomain == "" {
@ -745,6 +770,7 @@ func setOrgID(orgViewProvider orgViewProvider, request *model.AuthRequest) error
}
request.RequestedOrgID = org.ID
request.RequestedOrgName = org.Name
request.RequestedPrimaryDomain = primaryDomain
return nil
}

View File

@ -95,6 +95,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es
handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount, es}),
newProjectRole(handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount, es},
repos.ProjectEvents),
newLabelPolicy(handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount, es}),
}
}

View File

@ -0,0 +1,104 @@
package handler
import (
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/query"
"github.com/caos/zitadel/internal/eventstore/spooler"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model"
iam_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
)
const (
labelPolicyTable = "auth.label_policies"
)
type LabelPolicy struct {
handler
subscription *eventstore.Subscription
}
func newLabelPolicy(handler handler) *LabelPolicy {
h := &LabelPolicy{
handler: handler,
}
h.subscribe()
return h
}
func (m *LabelPolicy) subscribe() {
m.subscription = m.es.Subscribe(m.AggregateTypes()...)
go func() {
for event := range m.subscription.Events {
query.ReduceEvent(m, event)
}
}()
}
func (m *LabelPolicy) ViewModel() string {
return labelPolicyTable
}
func (_ *LabelPolicy) AggregateTypes() []models.AggregateType {
return []models.AggregateType{model.OrgAggregate, iam_es_model.IAMAggregate}
}
func (m *LabelPolicy) CurrentSequence() (uint64, error) {
sequence, err := m.view.GetLatestLabelPolicySequence()
if err != nil {
return 0, err
}
return sequence.CurrentSequence, nil
}
func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestLabelPolicySequence()
if err != nil {
return nil, err
}
return es_models.NewSearchQuery().
AggregateTypeFilter(m.AggregateTypes()...).
LatestSequenceFilter(sequence.CurrentSequence), nil
}
func (m *LabelPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processLabelPolicy(event)
}
return err
}
func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
policy := new(iam_model.LabelPolicyView)
switch event.Type {
case iam_es_model.LabelPolicyAdded, model.LabelPolicyAdded:
err = policy.AppendEvent(event)
case iam_es_model.LabelPolicyChanged, model.LabelPolicyChanged:
policy, err = m.view.LabelPolicyByAggregateID(event.AggregateID)
if err != nil {
return err
}
err = policy.AppendEvent(event)
default:
return m.view.ProcessedLabelPolicySequence(event)
}
if err != nil {
return err
}
return m.view.PutLabelPolicy(policy, event)
}
func (m *LabelPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip)
}
func (m *LabelPolicy) OnSuccess() error {
return spooler.HandleSuccess(m.view.UpdateLabelPolicySpoolerRunTimestamp)
}

View File

@ -0,0 +1,53 @@
package view
import (
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository"
)
const (
labelPolicyTable = "auth.label_policies"
)
func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyView, error) {
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
}
func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, event *models.Event) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil {
return err
}
return v.ProcessedLabelPolicySequence(event)
}
func (v *View) DeleteLabelPolicy(aggregateID string, event *models.Event) error {
err := view.DeleteLabelPolicy(v.Db, labelPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) {
return err
}
return v.ProcessedLabelPolicySequence(event)
}
func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(labelPolicyTable)
}
func (v *View) ProcessedLabelPolicySequence(event *models.Event) error {
return v.saveCurrentSequence(labelPolicyTable, event)
}
func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(labelPolicyTable)
}
func (v *View) GetLatestLabelPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {
return v.latestFailedEvent(labelPolicyTable, sequence)
}
func (v *View) ProcessedLabelPolicyFailedEvent(failedEvent *global_view.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@ -27,23 +27,26 @@ type AuthRequest struct {
MaxAuthAge uint32
Request Request
levelOfAssurance LevelOfAssurance
UserID string
LoginName string
DisplayName string
UserOrgID string
RequestedOrgID string
RequestedOrgName string
SelectedIDPConfigID string
LinkingUsers []*ExternalUser
PossibleSteps []NextStep
PasswordVerified bool
MFAsVerified []MFAType
Audience []string
AuthTime time.Time
Code string
LoginPolicy *model.LoginPolicyView
AllowedExternalIDPs []*model.IDPProviderView
levelOfAssurance LevelOfAssurance
UserID string
UserName string
LoginName string
DisplayName string
UserOrgID string
RequestedOrgID string
RequestedOrgName string
RequestedPrimaryDomain string
SelectedIDPConfigID string
LinkingUsers []*ExternalUser
PossibleSteps []NextStep
PasswordVerified bool
MFAsVerified []MFAType
Audience []string
AuthTime time.Time
Code string
LoginPolicy *model.LoginPolicyView
LabelPolicy *model.LabelPolicyView
AllowedExternalIDPs []*model.IDPProviderView
}
type ExternalUser struct {
@ -123,8 +126,9 @@ func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest {
return a
}
func (a *AuthRequest) SetUserInfo(userID, loginName, displayName, userOrgID string) {
func (a *AuthRequest) SetUserInfo(userID, userName, loginName, displayName, userOrgID string) {
a.UserID = userID
a.UserName = userName
a.LoginName = loginName
a.DisplayName = displayName
a.UserOrgID = userOrgID

View File

@ -50,6 +50,7 @@ func (s *SelectUserStep) Type() NextStepType {
type UserSelection struct {
UserID string
DisplayName string
UserName string
LoginName string
UserSessionState UserSessionState
SelectionPossible bool

View File

@ -7,10 +7,11 @@ import (
type LabelPolicy struct {
models.ObjectRoot
State PolicyState
Default bool
PrimaryColor string
SecondaryColor string
State PolicyState
Default bool
PrimaryColor string
SecondaryColor string
HideLoginNameSuffix bool
}
func (p *LabelPolicy) IsValid() bool {

View File

@ -7,10 +7,11 @@ import (
)
type LabelPolicyView struct {
AggregateID string
PrimaryColor string
SecondaryColor string
Default bool
AggregateID string
PrimaryColor string
SecondaryColor string
HideLoginNameSuffix bool
Default bool
CreationDate time.Time
ChangeDate time.Time

View File

@ -11,26 +11,29 @@ import (
type LabelPolicy struct {
models.ObjectRoot
State int32 `json:"-"`
PrimaryColor string `json:"primaryColor"`
SecondaryColor string `json:"secondaryColor"`
State int32 `json:"-"`
PrimaryColor string `json:"primaryColor"`
SecondaryColor string `json:"secondaryColor"`
HideLoginNameSuffix bool `json:"hideLoginNameSuffix"`
}
func LabelPolicyToModel(policy *LabelPolicy) *iam_model.LabelPolicy {
return &iam_model.LabelPolicy{
ObjectRoot: policy.ObjectRoot,
State: iam_model.PolicyState(policy.State),
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
ObjectRoot: policy.ObjectRoot,
State: iam_model.PolicyState(policy.State),
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
}
}
func LabelPolicyFromModel(policy *iam_model.LabelPolicy) *LabelPolicy {
return &LabelPolicy{
ObjectRoot: policy.ObjectRoot,
State: int32(policy.State),
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
ObjectRoot: policy.ObjectRoot,
State: int32(policy.State),
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
}
}

View File

@ -24,34 +24,37 @@ type LabelPolicyView struct {
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:label_policy_state"`
PrimaryColor string `json:"primaryColor" gorm:"column:primary_color"`
SecondaryColor string `json:"secondaryColor" gorm:"column:secondary_color"`
Default bool `json:"-" gorm:"-"`
PrimaryColor string `json:"primaryColor" gorm:"column:primary_color"`
SecondaryColor string `json:"secondaryColor" gorm:"column:secondary_color"`
HideLoginNameSuffix bool `json:"hideLoginNameSuffix" gorm:"column:hide_login_name_suffix"`
Default bool `json:"-" gorm:"-"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
}
func LabelPolicyViewFromModel(policy *model.LabelPolicyView) *LabelPolicyView {
return &LabelPolicyView{
AggregateID: policy.AggregateID,
Sequence: policy.Sequence,
CreationDate: policy.CreationDate,
ChangeDate: policy.ChangeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
Default: policy.Default,
AggregateID: policy.AggregateID,
Sequence: policy.Sequence,
CreationDate: policy.CreationDate,
ChangeDate: policy.ChangeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
Default: policy.Default,
}
}
func LabelPolicyViewToModel(policy *LabelPolicyView) *model.LabelPolicyView {
return &model.LabelPolicyView{
AggregateID: policy.AggregateID,
Sequence: policy.Sequence,
CreationDate: policy.CreationDate,
ChangeDate: policy.ChangeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
Default: policy.Default,
AggregateID: policy.AggregateID,
Sequence: policy.Sequence,
CreationDate: policy.CreationDate,
ChangeDate: policy.ChangeDate,
PrimaryColor: policy.PrimaryColor,
SecondaryColor: policy.SecondaryColor,
HideLoginNameSuffix: policy.HideLoginNameSuffix,
Default: policy.Default,
}
}

View File

@ -326,6 +326,32 @@ func (repo *OrgRepository) GetLabelPolicy(ctx context.Context) (*iam_model.Label
return iam_es_model.LabelPolicyViewToModel(policy), err
}
func (repo *OrgRepository) GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error) {
policy, viewErr := repo.View.LabelPolicyByAggregateID(repo.SystemDefaults.IamID)
if viewErr != nil && !errors.IsNotFound(viewErr) {
return nil, viewErr
}
if errors.IsNotFound(viewErr) {
policy = new(iam_es_model.LabelPolicyView)
}
events, esErr := repo.IAMEventstore.IAMEventsByID(ctx, repo.SystemDefaults.IamID, policy.Sequence)
if errors.IsNotFound(viewErr) && len(events) == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-3Nf8sd", "Errors.IAM.LabelPolicy.NotFound")
}
if esErr != nil {
logging.Log("EVENT-28uLp").WithError(esErr).Debug("error retrieving new events")
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
policyCopy := *policy
for _, event := range events {
if err := policyCopy.AppendEvent(event); err != nil {
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
}
policy.Default = true
return iam_es_model.LabelPolicyViewToModel(policy), nil
}
func (repo *OrgRepository) AddLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error) {
policy.AggregateID = authz.GetCtxData(ctx).OrgID
return repo.OrgEventstore.AddLabelPolicy(ctx, policy)
@ -336,6 +362,13 @@ func (repo *OrgRepository) ChangeLabelPolicy(ctx context.Context, policy *iam_mo
return repo.OrgEventstore.ChangeLabelPolicy(ctx, policy)
}
func (repo *OrgRepository) RemoveLabelPolicy(ctx context.Context) error {
policy := &iam_model.LabelPolicy{ObjectRoot: models.ObjectRoot{
AggregateID: authz.GetCtxData(ctx).OrgID,
}}
return repo.OrgEventstore.RemoveLabelPolicy(ctx, policy)
}
func (repo *OrgRepository) GetLoginPolicy(ctx context.Context) (*iam_model.LoginPolicyView, error) {
policy, viewErr := repo.View.LoginPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
if viewErr != nil && !errors.IsNotFound(viewErr) {

View File

@ -82,6 +82,26 @@ func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*us
return repo.UserEvents.CreateUser(ctx, user, pwPolicyView, orgPolicyView)
}
func (repo *UserRepo) ImportUser(ctx context.Context, user *usr_model.User, passwordChangeRequired bool) (*usr_model.User, error) {
pwPolicy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
if err != nil && caos_errs.IsNotFound(err) {
pwPolicy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
}
if err != nil {
return nil, err
}
pwPolicyView := iam_es_model.PasswordComplexityViewToModel(pwPolicy)
orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
if err != nil && errors.IsNotFound(err) {
orgPolicy, err = repo.View.OrgIAMPolicyByAggregateID(repo.SystemDefaults.IamID)
}
if err != nil {
return nil, err
}
orgPolicyView := iam_es_model.OrgIAMViewToModel(orgPolicy)
return repo.UserEvents.ImportUser(ctx, user, pwPolicyView, orgPolicyView, passwordChangeRequired)
}
func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
policyResourceOwner := authz.GetCtxData(ctx).OrgID
if resourceOwner != "" {

View File

@ -86,4 +86,10 @@ type OrgRepository interface {
AddMailText(ctx context.Context, mailText *iam_model.MailText) (*iam_model.MailText, error)
ChangeMailText(ctx context.Context, mailText *iam_model.MailText) (*iam_model.MailText, error)
RemoveMailText(ctx context.Context, mailText *iam_model.MailText) error
GetLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
GetDefaultLabelPolicy(ctx context.Context) (*iam_model.LabelPolicyView, error)
AddLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error)
ChangeLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) (*iam_model.LabelPolicy, error)
RemoveLabelPolicy(ctx context.Context) error
}

View File

@ -10,6 +10,7 @@ import (
type UserRepository interface {
UserByID(ctx context.Context, id string) (*model.UserView, error)
CreateUser(ctx context.Context, user *model.User) (*model.User, error)
ImportUser(ctx context.Context, user *model.User, passwordChangeRequired bool) (*model.User, error)
RegisterUser(ctx context.Context, user *model.User, resourceOwner string) (*model.User, error)
DeactivateUser(ctx context.Context, id string) (*model.User, error)
ReactivateUser(ctx context.Context, id string) (*model.User, error)

View File

@ -758,6 +758,20 @@ func (es *OrgEventstore) ChangeLabelPolicy(ctx context.Context, policy *iam_mode
return iam_es_model.LabelPolicyToModel(repoOrg.LabelPolicy), nil
}
func (es *OrgEventstore) RemoveLabelPolicy(ctx context.Context, policy *iam_model.LabelPolicy) error {
if policy == nil || !policy.IsValid() {
return errors.ThrowPreconditionFailed(nil, "EVENT-M9gs", "Errors.Org.LabelPolicy.Invalid")
}
org, err := es.OrgByID(ctx, org_model.NewOrg(policy.AggregateID))
if err != nil {
return err
}
repoOrg := model.OrgFromModel(org)
addAggregate := LabelPolicyRemovedAggregate(es.Eventstore.AggregateCreator(), repoOrg)
return es_sdk.Push(ctx, es.PushAggregates, repoOrg.AppendEvents, addAggregate)
}
func (es *OrgEventstore) AddLoginPolicy(ctx context.Context, policy *iam_model.LoginPolicy) (*iam_model.LoginPolicy, error) {
if policy == nil || !policy.IsValid() {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-Sjkl9", "Errors.Org.LoginPolicy.Invalid")

View File

@ -54,7 +54,8 @@ func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) {
return
}
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.CheckLoginName(r.Context(), authReq.ID, data.LoginName, userAgentID)
loginName := data.LoginName
err = l.authRepo.CheckLoginName(r.Context(), authReq.ID, loginName, userAgentID)
if err != nil {
l.renderLogin(w, r, authReq, err)
return
@ -73,7 +74,7 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *mod
return authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowUsernamePassword
},
"hasExternalLogin": func() bool {
return authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0
return authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0
},
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogin], data, funcs)

View File

@ -265,15 +265,17 @@ func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title s
ErrType: errType,
ErrMessage: errMessage,
},
Lang: l.renderer.Lang(r).String(),
Title: title,
Theme: l.getTheme(r),
ThemeMode: l.getThemeMode(r),
OrgID: l.getOrgID(authReq),
OrgName: l.getOrgName(authReq),
AuthReqID: getRequestID(authReq, r),
CSRF: csrf.TemplateField(r),
Nonce: http_mw.GetNonce(r),
Lang: l.renderer.Lang(r).String(),
Title: title,
Theme: l.getTheme(r),
ThemeMode: l.getThemeMode(r),
OrgID: l.getOrgID(authReq),
OrgName: l.getOrgName(authReq),
PrimaryDomain: l.getOrgPrimaryDomain(authReq),
DisplayLoginNameSuffix: l.isDisplayLoginNameSuffix(authReq),
AuthReqID: getRequestID(authReq, r),
CSRF: csrf.TemplateField(r),
Nonce: http_mw.GetNonce(r),
}
if authReq != nil {
baseData.LoginPolicy = authReq.LoginPolicy
@ -283,12 +285,14 @@ func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title s
}
func (l *Login) getProfileData(authReq *model.AuthRequest) profileData {
var loginName, displayName string
var userName, loginName, displayName string
if authReq != nil {
userName = authReq.UserName
loginName = authReq.LoginName
displayName = authReq.DisplayName
}
return profileData{
UserName: userName,
LoginName: loginName,
DisplayName: displayName,
}
@ -329,6 +333,23 @@ func (l *Login) getOrgName(authReq *model.AuthRequest) string {
return authReq.RequestedOrgName
}
func (l *Login) getOrgPrimaryDomain(authReq *model.AuthRequest) string {
if authReq == nil {
return ""
}
return authReq.RequestedPrimaryDomain
}
func (l *Login) isDisplayLoginNameSuffix(authReq *model.AuthRequest) bool {
if authReq == nil {
return false
}
if authReq.RequestedOrgID == "" {
return false
}
return authReq.LabelPolicy != nil && !authReq.LabelPolicy.HideLoginNameSuffix
}
func getRequestID(authReq *model.AuthRequest, r *http.Request) string {
if authReq != nil {
return authReq.ID
@ -351,17 +372,19 @@ func (l *Login) cspErrorHandler(err error) http.Handler {
type baseData struct {
errorData
Lang string
Title string
Theme string
ThemeMode string
OrgID string
OrgName string
AuthReqID string
CSRF template.HTML
Nonce string
LoginPolicy *iam_model.LoginPolicyView
IDPProviders []*iam_model.IDPProviderView
Lang string
Title string
Theme string
ThemeMode string
OrgID string
OrgName string
PrimaryDomain string
DisplayLoginNameSuffix bool
AuthReqID string
CSRF template.HTML
Nonce string
LoginPolicy *iam_model.LoginPolicyView
IDPProviders []*iam_model.IDPProviderView
}
type errorData struct {
@ -380,6 +403,7 @@ type userData struct {
type profileData struct {
LoginName string
UserName string
DisplayName string
}

View File

@ -6,7 +6,7 @@ Login:
Loginname: Loginname
LoginnamePlaceHolder: username@domain
ExternalLogin: Login with an external user.
MustBeMemberOfOrg: The user must be mermber of the {{.OrgDomain}} organisation.
MustBeMemberOfOrg: The user must be mermber of the {{.OrgName}} organisation.
UserSelection:
Title: Select account
@ -16,7 +16,7 @@ UserSelection:
OtherUser: Other User
SessionState0: active
SessionState1: inactive
MustBeMemberOfOrg: The user must be mermber of the {{.OrgDomain}} organisation.
MustBeMemberOfOrg: The user must be mermber of the {{.OrgName}} organisation.
Password:
Title: Password

View File

@ -12,6 +12,11 @@ $lgn-container-margin: 0px auto 50px auto;
align-items: center;
border: none;
outline: none;
cursor: pointer;
&:disabled {
cursor: not-allowed;
}
.left {
padding: .5rem 1rem;

View File

@ -25,7 +25,6 @@
color: inherit;
background: transparent;
box-shadow: inset 0 -1px lgn-color($foreground, footer-line);
cursor: pointer;
&:hover {
$primary: map-get($config, primary);

View File

@ -440,6 +440,10 @@ i {
align-items: center;
border: none;
outline: none;
cursor: pointer;
}
.lgn-account-selection .lgn-account:disabled {
cursor: not-allowed;
}
.lgn-account-selection .lgn-account .left {
padding: 0.5rem 1rem;
@ -1298,6 +1302,10 @@ i {
align-items: center;
border: none;
outline: none;
cursor: pointer;
}
.lgn-account-selection .lgn-account:disabled {
cursor: not-allowed;
}
.lgn-account-selection .lgn-account .left {
padding: 0.5rem 1rem;

File diff suppressed because one or more lines are too long

View File

@ -440,6 +440,10 @@ i {
align-items: center;
border: none;
outline: none;
cursor: pointer;
}
.lgn-account-selection .lgn-account:disabled {
cursor: not-allowed;
}
.lgn-account-selection .lgn-account .left {
padding: 0.5rem 1rem;
@ -1202,7 +1206,6 @@ a:hover, a:active {
color: inherit;
background: transparent;
box-shadow: inset 0 -1px #303131;
cursor: pointer;
}
.lgn-account-selection .lgn-account:hover {
background-color: rgba(255, 255, 255, 0.02);
@ -1522,7 +1525,6 @@ a:hover, a:active {
color: inherit;
background: transparent;
box-shadow: inset 0 -1px #303131;
cursor: pointer;
}
.lgn-dark-theme .lgn-account-selection .lgn-account:hover {
background-color: rgba(255, 255, 255, 0.02);
@ -1836,7 +1838,6 @@ a:hover, a:active {
color: inherit;
background: transparent;
box-shadow: inset 0 -1px #e3e8ee;
cursor: pointer;
}
.lgn-light-theme .lgn-account-selection .lgn-account:hover {
background-color: rgba(0, 0, 0, 0.02);

File diff suppressed because one or more lines are too long

View File

@ -20,8 +20,13 @@
{{if hasUsernamePasswordLogin }}
<div class="fields">
<label class="lgn-label" for="loginName">{{t "Login.Loginname"}}</label>
<div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="loginName" name="loginName" placeholder="{{t "Login.LoginnamePlaceHolder"}}"
value="{{ .LoginName }}" {{if .ErrMessage}}shake {{end}} autocomplete="username" autofocus required>
value="{{ .UserName }}" {{if .ErrMessage}}shake {{end}} autocomplete="username" autofocus required>
{{if .DisplayLoginNameSuffix}}
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
{{end}}
</div>
</div>
{{end}}
@ -53,5 +58,6 @@
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
<script src="{{ resourceUrl "scripts/input_suffix_offset.js" }}"></script>
{{template "main-bottom" .}}

View File

@ -23,10 +23,11 @@
<div class="lgn-account-selection">
{{ if .Users }}
{{ $displayLoginNameSuffix := and .OrgID (not .DisplayLoginNameSuffix)}}
{{ range $user := .Users }}
{{ $sessionState := (printf "UserSelection.SessionState%v" $user.UserSessionState) }}
<button type="submit" name="userID" value="{{$user.UserID}}" class="lgn-account"
{{if not $user.SelectionPossible}}disabled title="{{t " Errors.User.NotAllowedOrg"}}"{{end}}>
{{if not $user.SelectionPossible}}disabled title="{{t "Errors.User.NotAllowedOrg"}}"{{end}}>
<div class="left">
<div class="lgn-avatar" displayname="{{$user.DisplayName}}">
<span class="initials">A</span>
@ -34,7 +35,7 @@
</div>
<div class="lgn-names">
<p class="lgn-displayname">{{$user.DisplayName}}</p>
<p class="lgn-loginname">{{$user.LoginName}}</p>
<p class="lgn-loginname">{{if and $displayLoginNameSuffix $user.SelectionPossible}}{{$user.UserName}}{{else}}{{$user.LoginName}}{{end}}</p>
<p class="lgn-session-state i{{$user.UserSessionState}}">{{t $sessionState}}</p>
</div>
<span class="fill-space"></span>

View File

@ -1,5 +1,5 @@
{{define "user-profile"}}
{{if .LoginName}}
{{if or .LoginName .UserName}}
<div class="lgn-login-profile">
<div class="lgn-profile-image"></div>
<div class="lgn-names">
@ -9,7 +9,7 @@
</div>
</div>
<div class="lgn-loginname">
<p>{{.LoginName}}</p>
<p>{{if .DisplayLoginNameSuffix}}{{.LoginName}}{{else}}{{.UserName}}{{end}}</p>
</div>
</div>
</div>

View File

@ -93,9 +93,6 @@ func (u *User) CheckOrgIamPolicy(policy *iam_model.OrgIAMPolicy) error {
if policy == nil {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-zSH7j", "Errors.Users.OrgIamPolicyNil")
}
if policy.UserLoginMustBeDomain && strings.Contains(u.UserName, "@") {
return caos_errors.ThrowPreconditionFailed(nil, "MODEL-se4sJ", "Errors.User.EmailAsUsernameNotAllowed")
}
if !policy.UserLoginMustBeDomain && u.Profile != nil && u.UserName == "" && u.Email != nil {
u.UserName = u.EmailAddress
}

View File

@ -145,7 +145,7 @@ func (es *UserEventstore) prepareCreateMachine(ctx context.Context, user *usr_mo
return machine, createAggregates, err
}
func (es *UserEventstore) prepareCreateHuman(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
func (es *UserEventstore) prepareCreateHuman(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView, changePasswordRequired bool, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
err := user.CheckOrgIAMPolicy(orgIAMPolicy)
if err != nil {
return nil, nil, err
@ -155,7 +155,7 @@ func (es *UserEventstore) prepareCreateHuman(ctx context.Context, user *usr_mode
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-LoIxJ", "Errors.User.Invalid")
}
err = user.HashPasswordIfExisting(pwPolicy, es.PasswordAlg, true)
err = user.HashPasswordIfExisting(pwPolicy, es.PasswordAlg, changePasswordRequired)
if err != nil {
return nil, nil, err
}
@ -177,7 +177,7 @@ func (es *UserEventstore) prepareCreateHuman(ctx context.Context, user *usr_mode
return repoUser, createAggregates, err
}
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView, changePasswordRequired bool, resourceOwner string) (*model.User, []*es_models.Aggregate, error) {
id, err := es.idGenerator.Next()
if err != nil {
return nil, nil, err
@ -185,7 +185,7 @@ func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model
user.AggregateID = id
if user.Human != nil {
return es.prepareCreateHuman(ctx, user, pwPolicy, orgIAMPolicy, resourceOwner)
return es.prepareCreateHuman(ctx, user, pwPolicy, orgIAMPolicy, changePasswordRequired, resourceOwner)
} else if user.Machine != nil {
return es.prepareCreateMachine(ctx, user, orgIAMPolicy, resourceOwner)
}
@ -193,7 +193,22 @@ func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model
}
func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView) (*usr_model.User, error) {
repoUser, aggregates, err := es.PrepareCreateUser(ctx, user, pwPolicy, orgIAMPolicy, "")
repoUser, aggregates, err := es.PrepareCreateUser(ctx, user, pwPolicy, orgIAMPolicy, true, "")
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoUser.AppendEvents, aggregates...)
if err != nil {
return nil, err
}
es.userCache.cacheUser(repoUser)
return model.UserToModel(repoUser), nil
}
func (es *UserEventstore) ImportUser(ctx context.Context, user *usr_model.User, pwPolicy *iam_model.PasswordComplexityPolicyView, orgIAMPolicy *iam_model.OrgIAMPolicyView, changePasswordRequired bool) (*usr_model.User, error) {
repoUser, aggregates, err := es.PrepareCreateUser(ctx, user, pwPolicy, orgIAMPolicy, changePasswordRequired, "")
if err != nil {
return nil, err
}

View File

@ -0,0 +1,21 @@
ALTER TABLE management.label_policies ADD COLUMN hide_login_name_suffix BOOLEAN;
ALTER TABLE adminapi.label_policies ADD COLUMN hide_login_name_suffix BOOLEAN;
CREATE TABLE auth.label_policies (
aggregate_id TEXT,
creation_date TIMESTAMPTZ,
change_date TIMESTAMPTZ,
label_policy_state SMALLINT,
sequence BIGINT,
primary_color TEXT,
secondary_color TEXT,
hide_login_name_suffix BOOLEAN,
PRIMARY KEY (aggregate_id)
);
GRANT SELECT ON TABLE auth.label_policies TO notification;

View File

@ -1020,11 +1020,13 @@ message DefaultLabelPolicy {
string secondary_color = 2;
google.protobuf.Timestamp creation_date = 3;
google.protobuf.Timestamp change_date = 4;
bool hide_login_name_suffix = 5;
}
message DefaultLabelPolicyUpdate {
string primary_color = 1;
string secondary_color = 2;
bool hide_login_name_suffix = 3;
}
message DefaultLabelPolicyView {
@ -1032,6 +1034,7 @@ message DefaultLabelPolicyView {
string secondary_color = 2;
google.protobuf.Timestamp creation_date = 3;
google.protobuf.Timestamp change_date = 4;
bool hide_login_name_suffix = 5;
}
message DefaultMailTemplate {

View File

@ -114,6 +114,17 @@ service ManagementService {
};
}
rpc ImportHuman(ImportHumanRequest) returns (UserResponse) {
option (google.api.http) = {
post: "/users/humans/_import"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.write"
};
}
rpc DeactivateUser(UserID) returns (UserResponse) {
option (google.api.http) = {
put: "/users/{id}/_deactivate"
@ -1809,6 +1820,58 @@ service ManagementService {
};
}
rpc GetLabelPolicy(google.protobuf.Empty) returns (LabelPolicyView) {
option (google.api.http) = {
get: "/orgs/me/policies/label"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "policy.read"
};
}
rpc GetDefaultLabelPolicy(google.protobuf.Empty) returns (LabelPolicyView) {
option (google.api.http) = {
get: "/orgs/default/policies/label"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "policy.read"
};
}
rpc CreateLabelPolicy(LabelPolicyRequest) returns (LabelPolicy) {
option (google.api.http) = {
post: "/orgs/me/policies/label"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "policy.write"
};
}
rpc UpdateLabelPolicy(LabelPolicyRequest) returns (LabelPolicy) {
option (google.api.http) = {
put: "/orgs/me/policies/label"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "policy.write"
};
}
rpc RemoveLabelPolicy(google.protobuf.Empty) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/orgs/me/policies/label"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "policy.delete"
};
}
}
message ZitadelDocs {
@ -1904,6 +1967,26 @@ message CreateUserRequest {
}
}
message ImportHumanRequest {
string user_name = 1 [(validate.rules).string.pattern = "^[^[:space:]]{1,200}$"];
string first_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
string last_name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
string nick_name = 4 [(validate.rules).string = {max_len: 200}];
string preferred_language = 5 [(validate.rules).string = {max_len: 200}];
Gender gender = 6;
string email = 7 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
bool is_email_verified = 8;
string phone = 9 [(validate.rules).string = {max_len: 20}];
bool is_phone_verified = 10;
string country = 11 [(validate.rules).string = {max_len: 200}];
string locality = 12 [(validate.rules).string = {max_len: 200}];
string postal_code = 13 [(validate.rules).string = {max_len: 200}];
string region = 14 [(validate.rules).string = {max_len: 200}];
string street_address = 15 [(validate.rules).string = {max_len: 200}];
string password = 16 [(validate.rules).string = {max_len: 72}];
bool password_change_required = 17;
}
message CreateHumanRequest {
string first_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
string last_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
@ -3657,3 +3740,28 @@ message MailTextView {
google.protobuf.Timestamp creation_date = 10;
google.protobuf.Timestamp change_date = 11;
}
message LabelPolicy {
string primary_color = 1;
string secondary_color = 2;
google.protobuf.Timestamp creation_date = 3;
google.protobuf.Timestamp change_date = 4;
bool hide_login_name_suffix = 5;
}
message LabelPolicyRequest {
string primary_color = 1;
string secondary_color = 2;
google.protobuf.Timestamp creation_date = 3;
google.protobuf.Timestamp change_date = 4;
bool hide_login_name_suffix = 5;
}
message LabelPolicyView {
bool default = 1;
string primary_color = 2;
string secondary_color = 3;
google.protobuf.Timestamp creation_date = 4;
google.protobuf.Timestamp change_date = 5;
bool hide_login_name_suffix = 6;
}