mirror of
https://github.com/zitadel/zitadel.git
synced 2025-05-22 12:38:20 +00:00
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:
parent
a012aed5cb
commit
03ddb8fc38
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
45
internal/api/grpc/management/label_policy.go
Normal file
45
internal/api/grpc/management/label_policy.go
Normal 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
|
||||
}
|
50
internal/api/grpc/management/label_policy_converter.go
Normal file
50
internal/api/grpc/management/label_policy_converter.go
Normal 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,
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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},
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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}),
|
||||
}
|
||||
}
|
||||
|
||||
|
104
internal/auth/repository/eventsourcing/handler/label_policy.go
Normal file
104
internal/auth/repository/eventsourcing/handler/label_policy.go
Normal 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)
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
|
@ -50,6 +50,7 @@ func (s *SelectUserStep) Type() NextStepType {
|
||||
type UserSelection struct {
|
||||
UserID string
|
||||
DisplayName string
|
||||
UserName string
|
||||
LoginName string
|
||||
UserSessionState UserSessionState
|
||||
SelectionPossible bool
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 != "" {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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
@ -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" .}}
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
21
migrations/cockroach/V1.33__label_policy.sql
Normal file
21
migrations/cockroach/V1.33__label_policy.sql
Normal 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;
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user