mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 04:57:33 +00:00
fix: claim verified domain from usernames (#603)
* fix: return orgDomain validationType * added missing translations for orgDomain activity * claim org domain * show message if domain token was requested * fix tests * fix tests Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
)
|
||||
|
||||
type OrgDomainView struct {
|
||||
OrgID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Domain string
|
||||
Primary bool
|
||||
Verified bool
|
||||
OrgID string
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Domain string
|
||||
Primary bool
|
||||
Verified bool
|
||||
ValidationType OrgDomainValidationType
|
||||
}
|
||||
|
||||
type OrgDomainSearchRequest struct {
|
||||
|
@@ -53,7 +53,7 @@ func StartOrg(conf OrgConfig, defaults systemdefaults.SystemDefaults) *OrgEvents
|
||||
}
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*model.Org, []*es_models.Aggregate, error) {
|
||||
func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org, users func(context.Context, string) ([]*es_models.Aggregate, error)) (*model.Org, []*es_models.Aggregate, error) {
|
||||
if orgModel == nil || !orgModel.IsValid() {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "Errors.Org.Invalid")
|
||||
}
|
||||
@@ -66,13 +66,13 @@ func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_mod
|
||||
orgModel.AggregateID = id
|
||||
org := model.OrgFromModel(orgModel)
|
||||
|
||||
aggregates, err := orgCreatedAggregates(ctx, es.AggregateCreator(), org)
|
||||
aggregates, err := orgCreatedAggregates(ctx, es.AggregateCreator(), org, users)
|
||||
|
||||
return org, aggregates, err
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) CreateOrg(ctx context.Context, orgModel *org_model.Org) (*org_model.Org, error) {
|
||||
org, aggregates, err := es.PrepareCreateOrg(ctx, orgModel)
|
||||
func (es *OrgEventstore) CreateOrg(ctx context.Context, orgModel *org_model.Org, users func(context.Context, string) ([]*es_models.Aggregate, error)) (*org_model.Org, error) {
|
||||
org, aggregates, err := es.PrepareCreateOrg(ctx, orgModel, users)
|
||||
err = es_sdk.PushAggregates(ctx, es.PushAggregates, org.AppendEvents, aggregates...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -222,7 +222,7 @@ func (es *OrgEventstore) GenerateOrgDomainValidation(ctx context.Context, domain
|
||||
return token, url, err
|
||||
}
|
||||
|
||||
func (es *OrgEventstore) ValidateOrgDomain(ctx context.Context, domain *org_model.OrgDomain) error {
|
||||
func (es *OrgEventstore) ValidateOrgDomain(ctx context.Context, domain *org_model.OrgDomain, users func(context.Context, string) ([]*es_models.Aggregate, error)) error {
|
||||
if domain == nil || !domain.IsValid() {
|
||||
return errors.ThrowPreconditionFailed(nil, "EVENT-R24hb", "Errors.Org.InvalidDomain")
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func (es *OrgEventstore) ValidateOrgDomain(ctx context.Context, domain *org_mode
|
||||
checkType, _ := d.ValidationType.CheckType()
|
||||
err = es.verificationValidator(d.Domain, validationCode, validationCode, checkType)
|
||||
if err == nil {
|
||||
orgAggregates, err := OrgDomainVerifiedAggregate(ctx, es.Eventstore.AggregateCreator(), repoOrg, repoDomain)
|
||||
orgAggregates, err := OrgDomainVerifiedAggregate(ctx, es.Eventstore.AggregateCreator(), repoOrg, repoDomain, users)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -578,6 +578,7 @@ func TestOrgEventstore_ValidateOrgDomain(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
domain *org_model.OrgDomain
|
||||
users func(ctx context.Context, domain string) ([]*es_models.Aggregate, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -682,6 +683,26 @@ func TestOrgEventstore_ValidateOrgDomain(t *testing.T) {
|
||||
isErr: errors.IsInternal,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "(user) aggregate fails",
|
||||
fields: fields{Eventstore: newTestEventstore(t).
|
||||
expectFilterEvents([]*es_models.Event{orgCreatedEvent(), orgDomainAddedEvent(), orgDomainVerificationAddedEvent("token")}, nil).
|
||||
expectDecrypt().
|
||||
expectVerification(true).
|
||||
expectAggregateCreator().
|
||||
expectPushEvents(0, errors.ThrowInternal(nil, "EVENT-S8WzW", "test")),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.NewMockContext("org", "user"),
|
||||
domain: &org_model.OrgDomain{ObjectRoot: es_models.ObjectRoot{AggregateID: "hodor-org"}, Domain: "hodor.org", ValidationType: org_model.OrgDomainValidationTypeHTTP},
|
||||
users: func(ctx context.Context, domain string) ([]*es_models.Aggregate, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "push failed",
|
||||
fields: fields{Eventstore: newTestEventstore(t).
|
||||
@@ -719,7 +740,7 @@ func TestOrgEventstore_ValidateOrgDomain(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.fields.Eventstore.ValidateOrgDomain(tt.args.ctx, tt.args.domain)
|
||||
err := tt.fields.Eventstore.ValidateOrgDomain(tt.args.ctx, tt.args.domain, tt.args.users)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got:%T %v", err, err)
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
org_model "github.com/caos/zitadel/internal/org/model"
|
||||
@@ -42,7 +43,7 @@ func OrgAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, i
|
||||
return aggCreator.NewAggregate(ctx, id, model.OrgAggregate, model.OrgVersion, sequence)
|
||||
}
|
||||
|
||||
func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *model.Org) (_ []*es_models.Aggregate, err error) {
|
||||
func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *model.Org, users func(context.Context, string) ([]*es_models.Aggregate, error)) (_ []*es_models.Aggregate, err error) {
|
||||
if org == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "Errors.Internal")
|
||||
}
|
||||
@@ -56,7 +57,7 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
return nil, err
|
||||
}
|
||||
aggregates := make([]*es_models.Aggregate, 0)
|
||||
aggregates, err = addDomainAggregateAndEvents(ctx, aggCreator, agg, aggregates, org)
|
||||
aggregates, err = addDomainAggregateAndEvents(ctx, aggCreator, agg, aggregates, org, users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -68,22 +69,18 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
|
||||
func addDomainAggregateAndEvents(ctx context.Context, aggCreator *es_models.AggregateCreator, orgAggregate *es_models.Aggregate, aggregates []*es_models.Aggregate, org *model.Org) ([]*es_models.Aggregate, error) {
|
||||
func addDomainAggregateAndEvents(ctx context.Context, aggCreator *es_models.AggregateCreator, orgAggregate *es_models.Aggregate, aggregates []*es_models.Aggregate, org *model.Org, users func(context.Context, string) ([]*es_models.Aggregate, error)) ([]*es_models.Aggregate, error) {
|
||||
for _, domain := range org.Domains {
|
||||
orgAggregate, err := orgAggregate.AppendEvent(model.OrgDomainAdded, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain.Verified {
|
||||
domainAggregate, err := reservedUniqueDomainAggregate(ctx, aggCreator, org.AggregateID, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregate)
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainVerified, domain)
|
||||
domainAggregates, err := OrgDomainVerifiedAggregate(ctx, aggCreator, org, domain, users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAggregates...)
|
||||
}
|
||||
if domain.Primary {
|
||||
orgAggregate, err = orgAggregate.AppendEvent(model.OrgDomainPrimarySet, domain)
|
||||
@@ -182,7 +179,6 @@ func reservedUniqueDomainAggregate(ctx context.Context, aggCreator *es_models.Ag
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isEventValidation(aggregate, model.OrgDomainReserved)), nil
|
||||
}
|
||||
|
||||
@@ -273,7 +269,7 @@ func OrgDomainValidationFailedAggregate(aggCreator *es_models.AggregateCreator,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainVerifiedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain) ([]*es_models.Aggregate, error) {
|
||||
func OrgDomainVerifiedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, domain *model.OrgDomain, users func(context.Context, string) ([]*es_models.Aggregate, error)) ([]*es_models.Aggregate, error) {
|
||||
if domain == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-DHs7s", "Errors.Internal")
|
||||
}
|
||||
@@ -291,6 +287,13 @@ func OrgDomainVerifiedAggregate(ctx context.Context, aggCreator *es_models.Aggre
|
||||
return nil, err
|
||||
}
|
||||
aggregates = append(aggregates, domainAgregate)
|
||||
if users != nil {
|
||||
userAggregates, err := users(ctx, domain.Domain)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowPreconditionFailed(err, "EVENT-HBwsw", "Errors.Internal")
|
||||
}
|
||||
aggregates = append(aggregates, userAggregates...)
|
||||
}
|
||||
return append(aggregates, agg), nil
|
||||
}
|
||||
|
||||
|
@@ -466,6 +466,7 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
ctx context.Context
|
||||
aggCreator *es_models.AggregateCreator
|
||||
org *model.Org
|
||||
users func(ctx context.Context, domain string) ([]*es_models.Aggregate, error)
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -523,6 +524,30 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
isErr: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org with domain users aggregate error",
|
||||
args: args{
|
||||
ctx: authz.NewMockContext("org", "user"),
|
||||
aggCreator: es_models.NewAggregateCreator("test"),
|
||||
org: &model.Org{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: "sdaf",
|
||||
Sequence: 5,
|
||||
},
|
||||
Name: "caos",
|
||||
Domains: []*model.OrgDomain{{
|
||||
Domain: "caos.ch",
|
||||
Verified: true,
|
||||
}},
|
||||
},
|
||||
users: func(ctx context.Context, domain string) ([]*es_models.Aggregate, error) {
|
||||
return nil, errors.ThrowInternal(nil, "id", "internal error")
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
isErr: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no name error",
|
||||
args: args{
|
||||
@@ -543,7 +568,7 @@ func TestOrgCreatedAggregates(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := orgCreatedAggregates(tt.args.ctx, tt.args.aggCreator, tt.args.org)
|
||||
got, err := orgCreatedAggregates(tt.args.ctx, tt.args.aggCreator, tt.args.org, tt.args.users)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
@@ -676,7 +701,7 @@ func TestOrgDomainVerifiedAggregates(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := OrgDomainVerifiedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.org, tt.args.domain)
|
||||
got, err := OrgDomainVerifiedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.org, tt.args.domain, nil)
|
||||
if tt.res.isErr == nil && err != nil {
|
||||
t.Errorf("no error expected got %T: %v", err, err)
|
||||
}
|
||||
|
@@ -2,12 +2,14 @@ package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/org/model"
|
||||
es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -18,11 +20,12 @@ const (
|
||||
)
|
||||
|
||||
type OrgDomainView struct {
|
||||
Domain string `json:"domain" gorm:"column:domain;primary_key"`
|
||||
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
|
||||
Verified bool `json:"-" gorm:"column:verified"`
|
||||
Primary bool `json:"-" gorm:"column:primary_domain"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
Domain string `json:"domain" gorm:"column:domain;primary_key"`
|
||||
OrgID string `json:"-" gorm:"column:org_id;primary_key"`
|
||||
Verified bool `json:"-" gorm:"column:verified"`
|
||||
Primary bool `json:"-" gorm:"column:primary_domain"`
|
||||
ValidationType int32 `json:"validationType" gorm:"column:validation_type"`
|
||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||
|
||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
||||
@@ -30,23 +33,25 @@ type OrgDomainView struct {
|
||||
|
||||
func OrgDomainViewFromModel(domain *model.OrgDomainView) *OrgDomainView {
|
||||
return &OrgDomainView{
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
ValidationType: int32(domain.ValidationType),
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgDomainToModel(domain *OrgDomainView) *model.OrgDomainView {
|
||||
return &model.OrgDomainView{
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
OrgID: domain.OrgID,
|
||||
Domain: domain.Domain,
|
||||
Primary: domain.Primary,
|
||||
Verified: domain.Verified,
|
||||
ValidationType: model.OrgDomainValidationType(domain.ValidationType),
|
||||
CreationDate: domain.CreationDate,
|
||||
ChangeDate: domain.ChangeDate,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +71,8 @@ func (d *OrgDomainView) AppendEvent(event *models.Event) (err error) {
|
||||
d.setRootData(event)
|
||||
d.CreationDate = event.CreationDate
|
||||
err = d.SetData(event)
|
||||
case es_model.OrgDomainVerificationAdded:
|
||||
err = d.SetData(event)
|
||||
case es_model.OrgDomainVerified:
|
||||
d.Verified = true
|
||||
case es_model.OrgDomainPrimarySet:
|
||||
|
Reference in New Issue
Block a user