feat: multiple domains (#188)

* check uniqueness on create and register user

* change user email, reserve release unique email

* usergrant unique aggregate

* usergrant uniqueness

* validate UserGrant

* fix tests

* domain is set on username in all orgs

* domain in admin

* org domain sql

* zitadel domain org name

* org domains

* org iam policy

* default org iam policy

* SETUP

* load login names

* login by login name

* login name

* fix: merge master

* fix: merge master

* Update internal/user/repository/eventsourcing/user.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* fix: fix unique domains

* fix: rename env variable

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi
2020-06-16 11:40:18 +02:00
committed by GitHub
parent 64b14b4e19
commit 7a6ca24625
109 changed files with 12578 additions and 6025 deletions

View File

@@ -0,0 +1,120 @@
package model
import (
"encoding/json"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/org/model"
)
type OrgDomain struct {
es_models.ObjectRoot `json:"-"`
Domain string `json:"domain"`
Verified bool `json:"-"`
Primary bool `json:"-"`
}
func GetDomain(domains []*OrgDomain, domain string) (int, *OrgDomain) {
for i, d := range domains {
if d.Domain == domain {
return i, d
}
}
return -1, nil
}
func (o *Org) appendAddDomainEvent(event *es_models.Event) error {
domain := new(OrgDomain)
err := domain.SetData(event)
if err != nil {
return err
}
domain.ObjectRoot.CreationDate = event.CreationDate
o.Domains = append(o.Domains, domain)
return nil
}
func (o *Org) appendRemoveDomainEvent(event *es_models.Event) error {
domain := new(OrgDomain)
err := domain.SetData(event)
if err != nil {
return err
}
if i, r := GetDomain(o.Domains, domain.Domain); r != nil {
o.Domains[i] = o.Domains[len(o.Domains)-1]
o.Domains[len(o.Domains)-1] = nil
o.Domains = o.Domains[:len(o.Domains)-1]
}
return nil
}
func (o *Org) appendVerifyDomainEvent(event *es_models.Event) error {
domain := new(OrgDomain)
err := domain.SetData(event)
if err != nil {
return err
}
if i, d := GetDomain(o.Domains, domain.Domain); d != nil {
d.Verified = true
o.Domains[i] = d
}
return nil
}
func (o *Org) appendPrimaryDomainEvent(event *es_models.Event) error {
domain := new(OrgDomain)
err := domain.SetData(event)
if err != nil {
return err
}
for _, d := range o.Domains {
d.Primary = false
if d.Domain == domain.Domain {
d.Primary = true
}
}
return nil
}
func (m *OrgDomain) SetData(event *es_models.Event) error {
err := json.Unmarshal(event.Data, m)
if err != nil {
return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data")
}
return nil
}
func OrgDomainsFromModel(domains []*model.OrgDomain) []*OrgDomain {
convertedDomainss := make([]*OrgDomain, len(domains))
for i, m := range domains {
convertedDomainss[i] = OrgDomainFromModel(m)
}
return convertedDomainss
}
func OrgDomainFromModel(domain *model.OrgDomain) *OrgDomain {
return &OrgDomain{
ObjectRoot: domain.ObjectRoot,
Domain: domain.Domain,
Verified: domain.Verified,
Primary: domain.Primary,
}
}
func OrgDomainsToModel(domains []*OrgDomain) []*model.OrgDomain {
convertedDomains := make([]*model.OrgDomain, len(domains))
for i, m := range domains {
convertedDomains[i] = OrgDomainToModel(m)
}
return convertedDomains
}
func OrgDomainToModel(domain *OrgDomain) *model.OrgDomain {
return &model.OrgDomain{
ObjectRoot: domain.ObjectRoot,
Domain: domain.Domain,
Verified: domain.Verified,
Primary: domain.Primary,
}
}

View File

@@ -14,33 +14,42 @@ const (
type Org struct {
es_models.ObjectRoot `json:"-"`
Name string `json:"name,omitempty"`
Domain string `json:"domain,omitempty"`
State int32 `json:"-"`
Name string `json:"name,omitempty"`
State int32 `json:"-"`
Members []*OrgMember `json:"-"`
Domains []*OrgDomain `json:"-"`
Members []*OrgMember `json:"-"`
OrgIamPolicy *OrgIamPolicy `json:"-"`
}
func OrgFromModel(org *org_model.Org) *Org {
members := OrgMembersFromModel(org.Members)
return &Org{
domains := OrgDomainsFromModel(org.Domains)
converted := &Org{
ObjectRoot: org.ObjectRoot,
Domain: org.Domain,
Name: org.Name,
State: int32(org.State),
Domains: domains,
Members: members,
}
if org.OrgIamPolicy != nil {
converted.OrgIamPolicy = OrgIamPolicyFromModel(org.OrgIamPolicy)
}
return converted
}
func OrgToModel(org *Org) *org_model.Org {
return &org_model.Org{
converted := &org_model.Org{
ObjectRoot: org.ObjectRoot,
Domain: org.Domain,
Name: org.Name,
State: org_model.OrgState(org.State),
Domains: OrgDomainsToModel(org.Domains),
Members: OrgMembersToModel(org.Members),
}
if org.OrgIamPolicy != nil {
converted.OrgIamPolicy = OrgIamPolicyToModel(org.OrgIamPolicy)
}
return converted
}
func OrgFromEvents(org *Org, events ...*es_models.Event) (*Org, error) {
@@ -101,6 +110,20 @@ func (o *Org) AppendEvent(event *es_models.Event) error {
return err
}
o.removeMember(member.UserID)
case OrgDomainAdded:
o.appendAddDomainEvent(event)
case OrgDomainVerified:
o.appendVerifyDomainEvent(event)
case OrgDomainPrimarySet:
o.appendPrimaryDomainEvent(event)
case OrgDomainRemoved:
o.appendRemoveDomainEvent(event)
case OrgIamPolicyAdded:
o.appendAddOrgIamPolicyEvent(event)
case OrgIamPolicyChanged:
o.appendChangeOrgIamPolicyEvent(event)
case OrgIamPolicyRemoved:
o.appendRemoveOrgIamPolicyEvent()
}
o.ObjectRoot.AppendEvent(event)
@@ -151,9 +174,6 @@ func (o *Org) Changes(changed *Org) map[string]interface{} {
if changed.Name != "" && changed.Name != o.Name {
changes["name"] = changed.Name
}
if changed.Domain != "" && changed.Domain != o.Domain {
changes["domain"] = changed.Domain
}
return changes
}

View File

@@ -0,0 +1,72 @@
package model
import (
"encoding/json"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgIamPolicy struct {
models.ObjectRoot
Description string `json:"description,omitempty"`
State int32 `json:"-"`
UserLoginMustBeDomain bool `json:"userLoginMustBeDomain"`
}
func OrgIamPolicyToModel(policy *OrgIamPolicy) *org_model.OrgIamPolicy {
return &org_model.OrgIamPolicy{
ObjectRoot: policy.ObjectRoot,
State: org_model.PolicyState(policy.State),
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
}
}
func OrgIamPolicyFromModel(policy *org_model.OrgIamPolicy) *OrgIamPolicy {
return &OrgIamPolicy{
ObjectRoot: policy.ObjectRoot,
State: int32(policy.State),
UserLoginMustBeDomain: policy.UserLoginMustBeDomain,
}
}
func (o *Org) appendAddOrgIamPolicyEvent(event *es_models.Event) error {
o.OrgIamPolicy = new(OrgIamPolicy)
err := o.OrgIamPolicy.SetData(event)
if err != nil {
return err
}
o.OrgIamPolicy.ObjectRoot.CreationDate = event.CreationDate
return nil
}
func (o *Org) appendChangeOrgIamPolicyEvent(event *es_models.Event) error {
return o.OrgIamPolicy.SetData(event)
}
func (o *Org) appendRemoveOrgIamPolicyEvent() {
o.OrgIamPolicy = nil
}
func (p *OrgIamPolicy) Changes(changed *OrgIamPolicy) map[string]interface{} {
changes := make(map[string]interface{}, 2)
if changed.Description != p.Description {
changes["description"] = changed.Description
}
if changed.UserLoginMustBeDomain != p.UserLoginMustBeDomain {
changes["userLoginMustBeDomain"] = changed.UserLoginMustBeDomain
}
return changes
}
func (p *OrgIamPolicy) SetData(event *es_models.Event) error {
err := json.Unmarshal(event.Data, p)
if err != nil {
return errors.ThrowInternal(err, "EVENT-7JS9d", "unable to unmarshal data")
}
return nil
}

View File

@@ -74,10 +74,10 @@ func TestAppendEvent(t *testing.T) {
{
name: "append change event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)},
org: &Org{Name: "OrgName", Domain: "asdf"},
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"name": "OrgName}`)},
org: &Org{Name: "OrgNameChanged"},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgNameChanged"},
},
{
name: "append deactivate event",
@@ -93,6 +93,13 @@ func TestAppendEvent(t *testing.T) {
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
},
{
name: "append added domain event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgDomainAdded},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -138,16 +145,6 @@ func TestChanges(t *testing.T) {
changesLen: 1,
},
},
{
name: "org domain changes",
args: args{
existing: &Org{Name: "Name", Domain: "old domain"},
new: &Org{Name: "Name", Domain: "new domain"},
},
res: res{
changesLen: 1,
},
},
{
name: "no changes",
args: args{

View File

@@ -7,11 +7,15 @@ const (
OrgDomainAggregate models.AggregateType = "org.domain"
OrgNameAggregate models.AggregateType = "org.name"
OrgAdded models.EventType = "org.added"
OrgChanged models.EventType = "org.changed"
OrgDeactivated models.EventType = "org.deactivated"
OrgReactivated models.EventType = "org.reactivated"
OrgRemoved models.EventType = "org.removed"
OrgAdded models.EventType = "org.added"
OrgChanged models.EventType = "org.changed"
OrgDeactivated models.EventType = "org.deactivated"
OrgReactivated models.EventType = "org.reactivated"
OrgRemoved models.EventType = "org.removed"
OrgDomainAdded models.EventType = "org.domain.added"
OrgDomainVerified models.EventType = "org.domain.verified"
OrgDomainRemoved models.EventType = "org.domain.removed"
OrgDomainPrimarySet models.EventType = "org.domain.primary.set"
OrgNameReserved models.EventType = "org.name.reserved"
OrgNameReleased models.EventType = "org.name.released"
@@ -22,4 +26,8 @@ const (
OrgMemberAdded models.EventType = "org.member.added"
OrgMemberChanged models.EventType = "org.member.changed"
OrgMemberRemoved models.EventType = "org.member.removed"
OrgIamPolicyAdded models.EventType = "org.iam.policy.added"
OrgIamPolicyChanged models.EventType = "org.iam.policy.changed"
OrgIamPolicyRemoved models.EventType = "org.iam.policy.removed"
)