mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:07:31 +00:00
feat: trusted (instance) domains (#8369)
# Which Problems Are Solved ZITADEL currently selects the instance context based on a HTTP header (see https://github.com/zitadel/zitadel/issues/8279#issue-2399959845 and checks it against the list of instance domains. Let's call it instance or API domain. For any context based URL (e.g. OAuth, OIDC, SAML endpoints, links in emails, ...) the requested domain (instance domain) will be used. Let's call it the public domain. In cases of proxied setups, all exposed domains (public domains) require the domain to be managed as instance domain. This can either be done using the "ExternalDomain" in the runtime config or via system API, which requires a validation through CustomerPortal on zitadel.cloud. # How the Problems Are Solved - Two new headers / header list are added: - `InstanceHostHeaders`: an ordered list (first sent wins), which will be used to match the instance. (For backward compatibility: the `HTTP1HostHeader`, `HTTP2HostHeader` and `forwarded`, `x-forwarded-for`, `x-forwarded-host` are checked afterwards as well) - `PublicHostHeaders`: an ordered list (first sent wins), which will be used as public host / domain. This will be checked against a list of trusted domains on the instance. - The middleware intercepts all requests to the API and passes a `DomainCtx` object with the hosts and protocol into the context (previously only a computed `origin` was passed) - HTTP / GRPC server do not longer try to match the headers to instances themself, but use the passed `http.DomainContext` in their interceptors. - The `RequestedHost` and `RequestedDomain` from authz.Instance are removed in favor of the `http.DomainContext` - When authenticating to or signing out from Console UI, the current `http.DomainContext(ctx).Origin` (already checked by instance interceptor for validity) is used to compute and dynamically add a `redirect_uri` and `post_logout_redirect_uri`. - Gateway passes all configured host headers (previously only did `x-zitadel-*`) - Admin API allows to manage trusted domain # Additional Changes None # Additional Context - part of #8279 - open topics: - "single-instance" mode - Console UI
This commit is contained in:
@@ -7,7 +7,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/ui/console"
|
||||
"github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -26,13 +26,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
zitadelProjectName = "ZITADEL"
|
||||
mgmtAppName = "Management-API"
|
||||
adminAppName = "Admin-API"
|
||||
authAppName = "Auth-API"
|
||||
consoleAppName = "Console"
|
||||
consoleRedirectPath = console.HandlerPrefix + "/auth/callback"
|
||||
consolePostLogoutPath = console.HandlerPrefix + "/signedout"
|
||||
zitadelProjectName = "ZITADEL"
|
||||
mgmtAppName = "Management-API"
|
||||
adminAppName = "Admin-API"
|
||||
authAppName = "Auth-API"
|
||||
consoleAppName = "Console"
|
||||
)
|
||||
|
||||
type InstanceSetup struct {
|
||||
@@ -233,7 +231,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
|
||||
func contextWithInstanceSetupInfo(ctx context.Context, instanceID, projectID, consoleAppID, externalDomain string) context.Context {
|
||||
return authz.WithConsole(
|
||||
authz.SetCtxData(
|
||||
authz.WithRequestedDomain(
|
||||
http.WithRequestedHost(
|
||||
authz.WithInstanceID(
|
||||
ctx,
|
||||
instanceID),
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/api/ui/console/path"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -74,7 +75,7 @@ func (c *Commands) RemoveInstanceDomain(ctx context.Context, instanceDomain stri
|
||||
}
|
||||
|
||||
func (c *Commands) addGeneratedInstanceDomain(ctx context.Context, a *instance.Aggregate, instanceName string) ([]preparation.Validation, error) {
|
||||
domain, err := c.GenerateDomain(instanceName, authz.GetInstance(ctx).RequestedDomain())
|
||||
domain, err := c.GenerateDomain(instanceName, http.DomainContext(ctx).RequestedDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -143,12 +144,12 @@ func (c *Commands) updateConsoleRedirectURIs(ctx context.Context, filter prepara
|
||||
if !appWriteModel.State.Exists() {
|
||||
return nil, nil
|
||||
}
|
||||
redirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + consoleRedirectPath
|
||||
redirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + path.RedirectPath
|
||||
changes := make([]project.OIDCConfigChanges, 0, 2)
|
||||
if !containsURI(appWriteModel.RedirectUris, redirectURI) {
|
||||
changes = append(changes, project.ChangeRedirectURIs(append(appWriteModel.RedirectUris, redirectURI)))
|
||||
}
|
||||
postLogoutRedirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + consolePostLogoutPath
|
||||
postLogoutRedirectURI := http.BuildHTTP(instanceDomain, c.externalPort, c.externalSecure) + path.PostLogoutPath
|
||||
if !containsURI(appWriteModel.PostLogoutRedirectUris, postLogoutRedirectURI) {
|
||||
changes = append(changes, project.ChangePostLogoutRedirectURIs(append(appWriteModel.PostLogoutRedirectUris, postLogoutRedirectURI)))
|
||||
}
|
||||
|
50
internal/command/instance_trusted_domain.go
Normal file
50
internal/command/instance_trusted_domain.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func (c *Commands) AddTrustedDomain(ctx context.Context, trustedDomain string) (*domain.ObjectDetails, error) {
|
||||
trustedDomain = strings.TrimSpace(trustedDomain)
|
||||
if trustedDomain == "" || len(trustedDomain) > 253 {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMA-Stk21", "Errors.Invalid.Argument")
|
||||
}
|
||||
if !allowDomainRunes.MatchString(trustedDomain) {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMA-S3v3w", "Errors.Instance.Domain.InvalidCharacter")
|
||||
}
|
||||
model := NewInstanceTrustedDomainsWriteModel(ctx)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if slices.Contains(model.Domains, trustedDomain) {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMA-hg42a", "Errors.Instance.Domain.AlreadyExists")
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, model, instance.NewTrustedDomainAddedEvent(ctx, InstanceAggregateFromWriteModel(&model.WriteModel), trustedDomain))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&model.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) RemoveTrustedDomain(ctx context.Context, trustedDomain string) (*domain.ObjectDetails, error) {
|
||||
model := NewInstanceTrustedDomainsWriteModel(ctx)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, model)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !slices.Contains(model.Domains, trustedDomain) {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMA-de3z9", "Errors.Instance.Domain.NotFound")
|
||||
}
|
||||
err = c.pushAppendAndReduce(ctx, model, instance.NewTrustedDomainRemovedEvent(ctx, InstanceAggregateFromWriteModel(&model.WriteModel), trustedDomain))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToObjectDetails(&model.WriteModel), nil
|
||||
}
|
197
internal/command/instance_trusted_domain_test.go
Normal file
197
internal/command/instance_trusted_domain_test.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func TestCommands_AddTrustedDomain(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
trustedDomain string
|
||||
}
|
||||
type want struct {
|
||||
details *domain.ObjectDetails
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "empty domain, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "",
|
||||
},
|
||||
want: want{
|
||||
err: zerrors.ThrowInvalidArgument(nil, "COMMA-Stk21", "Errors.Invalid.Argument"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid domain (length), error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "my-very-endleeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeess-looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0ooooooooooooooooooooooong.domain.com",
|
||||
},
|
||||
want: want{
|
||||
err: zerrors.ThrowInvalidArgument(nil, "COMMA-Stk21", "Errors.Invalid.Argument"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid domain (chars), error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "&.com",
|
||||
},
|
||||
want: want{
|
||||
err: zerrors.ThrowInvalidArgument(nil, "COMMA-S3v3w", "Errors.Instance.Domain.InvalidCharacter"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain already exists, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewTrustedDomainAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("instanceID").Aggregate, "domain.com"),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "domain.com",
|
||||
},
|
||||
want: want{
|
||||
err: zerrors.ThrowPreconditionFailed(nil, "COMMA-hg42a", "Errors.Instance.Domain.AlreadyExists"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain add ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
instance.NewTrustedDomainAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("instanceID").Aggregate, "domain.com"),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "domain.com",
|
||||
},
|
||||
want: want{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "instanceID",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
got, err := c.AddTrustedDomain(tt.args.ctx, tt.args.trustedDomain)
|
||||
assert.ErrorIs(t, err, tt.want.err)
|
||||
assert.Equal(t, tt.want.details, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_RemoveTrustedDomain(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
trustedDomain string
|
||||
}
|
||||
type want struct {
|
||||
details *domain.ObjectDetails
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "domain does not exists, error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "domain.com",
|
||||
},
|
||||
want: want{
|
||||
err: zerrors.ThrowNotFound(nil, "COMMA-de3z9", "Errors.Instance.Domain.NotFound"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "domain remove ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewTrustedDomainAddedEvent(context.Background(),
|
||||
&instance.NewAggregate("instanceID").Aggregate, "domain.com"),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
instance.NewTrustedDomainRemovedEvent(context.Background(),
|
||||
&instance.NewAggregate("instanceID").Aggregate, "domain.com"),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
trustedDomain: "domain.com",
|
||||
},
|
||||
want: want{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "instanceID",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
}
|
||||
got, err := c.RemoveTrustedDomain(tt.args.ctx, tt.args.trustedDomain)
|
||||
assert.ErrorIs(t, err, tt.want.err)
|
||||
assert.Equal(t, tt.want.details, got)
|
||||
})
|
||||
}
|
||||
}
|
54
internal/command/instance_trusted_domains_model.go
Normal file
54
internal/command/instance_trusted_domains_model.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
type InstanceTrustedDomainsWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
Domains []string
|
||||
}
|
||||
|
||||
func NewInstanceTrustedDomainsWriteModel(ctx context.Context) *InstanceTrustedDomainsWriteModel {
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
return &InstanceTrustedDomainsWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
InstanceID: instanceID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceTrustedDomainsWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *instance.TrustedDomainAddedEvent:
|
||||
wm.Domains = append(wm.Domains, e.Domain)
|
||||
case *instance.TrustedDomainRemovedEvent:
|
||||
wm.Domains = slices.DeleteFunc(wm.Domains, func(domain string) bool {
|
||||
return domain == e.Domain
|
||||
})
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceTrustedDomainsWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.TrustedDomainAddedEventType,
|
||||
instance.TrustedDomainRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
@@ -208,14 +208,6 @@ func (m *mockInstance) DefaultOrganisationID() string {
|
||||
return "defaultOrgID"
|
||||
}
|
||||
|
||||
func (m *mockInstance) RequestedDomain() string {
|
||||
return "zitadel.cloud"
|
||||
}
|
||||
|
||||
func (m *mockInstance) RequestedHost() string {
|
||||
return "zitadel.cloud:443"
|
||||
}
|
||||
|
||||
func (m *mockInstance) SecurityPolicyAllowedOrigins() []string {
|
||||
return nil
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -239,7 +240,7 @@ func AddOrgCommand(ctx context.Context, a *org.Aggregate, name string) preparati
|
||||
if name = strings.TrimSpace(name); name == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument")
|
||||
}
|
||||
defaultDomain, err := domain.NewIAMDomainName(name, authz.GetInstance(ctx).RequestedDomain())
|
||||
defaultDomain, err := domain.NewIAMDomainName(name, http_util.DomainContext(ctx).RequestedDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -708,7 +709,7 @@ func (c *Commands) addOrgWithID(ctx context.Context, organisation *domain.Org, o
|
||||
}
|
||||
|
||||
organisation.AggregateID = orgID
|
||||
organisation.AddIAMDomain(authz.GetInstance(ctx).RequestedDomain())
|
||||
organisation.AddIAMDomain(http_util.DomainContext(ctx).RequestedDomain())
|
||||
addedOrg := NewOrgWriteModel(organisation.AggregateID)
|
||||
|
||||
orgAgg := OrgAggregateFromWriteModel(&addedOrg.WriteModel)
|
||||
|
@@ -323,7 +323,7 @@ func (c *Commands) changeDefaultDomain(ctx context.Context, orgID, newName strin
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamDomain := authz.GetInstance(ctx).RequestedDomain()
|
||||
iamDomain := http_utils.DomainContext(ctx).RequestedDomain()
|
||||
defaultDomain, _ := domain.NewIAMDomainName(orgDomains.OrgName, iamDomain)
|
||||
isPrimary := defaultDomain == orgDomains.PrimaryDomain
|
||||
orgAgg := OrgAggregateFromWriteModel(&orgDomains.WriteModel)
|
||||
@@ -356,7 +356,7 @@ func (c *Commands) removeCustomDomains(ctx context.Context, orgID string) ([]eve
|
||||
return nil, err
|
||||
}
|
||||
hasDefault := false
|
||||
defaultDomain, _ := domain.NewIAMDomainName(orgDomains.OrgName, authz.GetInstance(ctx).RequestedDomain())
|
||||
defaultDomain, _ := domain.NewIAMDomainName(orgDomains.OrgName, http_utils.DomainContext(ctx).RequestedDomain())
|
||||
isPrimary := defaultDomain == orgDomains.PrimaryDomain
|
||||
orgAgg := OrgAggregateFromWriteModel(&orgDomains.WriteModel)
|
||||
events := make([]eventstore.Command, 0, len(orgDomains.Domains))
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"go.uber.org/mock/gomock"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
@@ -105,7 +104,7 @@ func TestAddDomain(t *testing.T) {
|
||||
Commands: []eventstore.Command{
|
||||
org.NewDomainAddedEvent(context.Background(), &agg.Aggregate, "domain"),
|
||||
org.NewDomainVerifiedEvent(context.Background(), &agg.Aggregate, "domain"),
|
||||
user.NewDomainClaimedEvent(context.Background(), &user.NewAggregate("userID1", "org2").Aggregate, "newID@temporary.domain", "username", false),
|
||||
user.NewDomainClaimedEvent(http.WithRequestedHost(context.Background(), "domain"), &user.NewAggregate("userID1", "org2").Aggregate, "newID@temporary.domain", "username", false),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -132,7 +131,7 @@ func TestAddDomain(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
AssertValidation(
|
||||
t,
|
||||
authz.WithRequestedDomain(context.Background(), "domain"),
|
||||
http.WithRequestedHost(context.Background(), "domain"),
|
||||
(&Commands{idGenerator: tt.args.idGenerator}).prepareAddOrgDomain(tt.args.a, tt.args.domain, tt.args.claimedUserIDs),
|
||||
tt.args.filter,
|
||||
tt.want,
|
||||
@@ -673,7 +672,7 @@ func TestCommandSide_GenerateOrgDomainValidation(t *testing.T) {
|
||||
|
||||
func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretGenerator crypto.Generator
|
||||
alg crypto.EncryptionAlgorithm
|
||||
@@ -697,9 +696,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "invalid domain, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -716,9 +713,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "missing aggregateid, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -733,8 +728,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "domain not exists, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -762,8 +756,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "domain already verified, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -803,8 +796,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "no code existing, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -838,8 +830,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "invalid domain verification, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -894,8 +885,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "domain verification, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -952,8 +942,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "domain verification, claimed users not found, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -1012,8 +1001,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
{
|
||||
name: "domain verification, claimed users, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(context.Background(),
|
||||
@@ -1067,7 +1055,7 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
&org.NewAggregate("org1").Aggregate,
|
||||
"domain.ch",
|
||||
),
|
||||
user.NewDomainClaimedEvent(context.Background(),
|
||||
user.NewDomainClaimedEvent(http.WithRequestedHost(context.Background(), "zitadel.ch"),
|
||||
&user.NewAggregate("user1", "org2").Aggregate,
|
||||
"tempid@temporary.zitadel.ch",
|
||||
"username@domain.ch",
|
||||
@@ -1100,13 +1088,13 @@ func TestCommandSide_ValidateOrgDomain(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
domainVerificationGenerator: tt.fields.secretGenerator,
|
||||
domainVerificationAlg: tt.fields.alg,
|
||||
domainVerificationValidator: tt.fields.domainValidationFunc,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
}
|
||||
got, err := r.ValidateOrgDomain(authz.WithRequestedDomain(tt.args.ctx, "zitadel.ch"), tt.args.domain, tt.args.claimedUserIDs)
|
||||
got, err := r.ValidateOrgDomain(http.WithRequestedHost(tt.args.ctx, "zitadel.ch"), tt.args.domain, tt.args.claimedUserIDs)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -65,7 +66,7 @@ func TestAddOrg(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
AssertValidation(t, context.Background(), AddOrgCommand(authz.WithRequestedDomain(context.Background(), "localhost"), tt.args.a, tt.args.name), nil, tt.want)
|
||||
AssertValidation(t, context.Background(), AddOrgCommand(http_util.WithRequestedHost(context.Background(), "localhost"), tt.args.a, tt.args.name), nil, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -229,7 +230,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
name: "Org",
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
@@ -297,7 +298,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
name: "Org",
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
@@ -360,7 +361,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
name: "Org",
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
@@ -431,7 +432,7 @@ func TestCommandSide_AddOrg(t *testing.T) {
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
name: " Org ",
|
||||
userID: "user1",
|
||||
resourceOwner: "org1",
|
||||
@@ -551,7 +552,7 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "zitadel.ch"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
|
||||
orgID: "org1",
|
||||
name: " org ",
|
||||
},
|
||||
@@ -581,7 +582,7 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "zitadel.ch"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
|
||||
orgID: "org1",
|
||||
name: "neworg",
|
||||
},
|
||||
@@ -635,7 +636,7 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "zitadel.ch"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
|
||||
orgID: "org1",
|
||||
name: "neworg",
|
||||
},
|
||||
@@ -695,7 +696,7 @@ func TestCommandSide_ChangeOrg(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "zitadel.ch"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "zitadel.ch"),
|
||||
orgID: "org1",
|
||||
name: "neworg",
|
||||
},
|
||||
@@ -1286,7 +1287,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "",
|
||||
},
|
||||
@@ -1304,7 +1305,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
@@ -1325,7 +1326,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
@@ -1418,7 +1419,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(
|
||||
context.Background(),
|
||||
http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
@@ -1441,7 +1442,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
@@ -1521,7 +1522,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID"),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
@@ -1621,7 +1622,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||
ctx: http_util.WithRequestedHost(context.Background(), "iam-domain"),
|
||||
setupOrg: &OrgSetup{
|
||||
Name: "Org",
|
||||
Admins: []*OrgSetupAdmin{
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -277,7 +277,7 @@ func (c *Commands) userDomainClaimed(ctx context.Context, userID string) (events
|
||||
user.NewDomainClaimedEvent(
|
||||
ctx,
|
||||
userAgg,
|
||||
fmt.Sprintf("%s@temporary.%s", id, authz.GetInstance(ctx).RequestedDomain()),
|
||||
fmt.Sprintf("%s@temporary.%s", id, http_util.DomainContext(ctx).RequestedDomain()),
|
||||
existingUser.UserName,
|
||||
domainPolicy.UserLoginMustBeDomain),
|
||||
}, changedUserGrant, nil
|
||||
@@ -305,7 +305,7 @@ func (c *Commands) prepareUserDomainClaimed(ctx context.Context, filter preparat
|
||||
return user.NewDomainClaimedEvent(
|
||||
ctx,
|
||||
userAgg,
|
||||
fmt.Sprintf("%s@temporary.%s", id, authz.GetInstance(ctx).RequestedDomain()),
|
||||
fmt.Sprintf("%s@temporary.%s", id, http_util.DomainContext(ctx).RequestedDomain()),
|
||||
userWriteModel.UserName,
|
||||
domainPolicy.UserLoginMustBeDomain), nil
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -107,7 +108,7 @@ func (c *Commands) createHumanTOTP(ctx context.Context, userID, resourceOwner st
|
||||
}
|
||||
issuer := c.multifactors.OTP.Issuer
|
||||
if issuer == "" {
|
||||
issuer = authz.GetInstance(ctx).RequestedDomain()
|
||||
issuer = http_util.DomainContext(ctx).RequestedDomain()
|
||||
}
|
||||
key, err := domain.NewTOTPKey(issuer, accountName)
|
||||
if err != nil {
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -534,7 +535,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
|
||||
ctx: http_util.WithRequestedHost(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
|
||||
resourceOwner: "org1",
|
||||
userID: "user1",
|
||||
},
|
||||
@@ -583,7 +584,7 @@ func TestCommands_createHumanTOTP(t *testing.T) {
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithRequestedDomain(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
|
||||
ctx: http_util.WithRequestedHost(authz.NewMockContext("instanceID", "org1", "user1"), "zitadel.com"),
|
||||
resourceOwner: "org1",
|
||||
userID: "user2",
|
||||
},
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
|
||||
func TestCommands_RegisterUserPasskey(t *testing.T) {
|
||||
ctx := authz.NewMockContextWithPermissions("instance1", "org1", "user1", nil)
|
||||
ctx = authz.WithRequestedDomain(ctx, "example.com")
|
||||
ctx = http_util.WithRequestedHost(ctx, "example.com")
|
||||
|
||||
webauthnConfig := &webauthn_helper.Config{
|
||||
DisplayName: "test",
|
||||
@@ -129,7 +130,7 @@ func TestCommands_RegisterUserPasskey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) {
|
||||
ctx := authz.WithRequestedDomain(context.Background(), "example.com")
|
||||
ctx := http_util.WithRequestedHost(context.Background(), "example.com")
|
||||
webauthnConfig := &webauthn_helper.Config{
|
||||
DisplayName: "test",
|
||||
ExternalSecure: true,
|
||||
@@ -231,7 +232,7 @@ func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommands_verifyUserPasskeyCode(t *testing.T) {
|
||||
ctx := authz.WithRequestedDomain(context.Background(), "example.com")
|
||||
ctx := http_util.WithRequestedHost(context.Background(), "example.com")
|
||||
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||
es := eventstoreExpect(t,
|
||||
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
||||
@@ -339,7 +340,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommands_pushUserPasskey(t *testing.T) {
|
||||
ctx := authz.WithRequestedDomain(authz.NewMockContext("instance1", "org1", "user1"), "example.com")
|
||||
ctx := http_util.WithRequestedHost(authz.NewMockContext("instance1", "org1", "user1"), "example.com")
|
||||
webauthnConfig := &webauthn_helper.Config{
|
||||
DisplayName: "test",
|
||||
ExternalSecure: true,
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
@@ -21,7 +22,7 @@ import (
|
||||
|
||||
func TestCommands_RegisterUserU2F(t *testing.T) {
|
||||
ctx := authz.NewMockContextWithPermissions("instance1", "org1", "user1", nil)
|
||||
ctx = authz.WithRequestedDomain(ctx, "example.com")
|
||||
ctx = http_util.WithRequestedHost(ctx, "example.com")
|
||||
|
||||
webauthnConfig := &webauthn_helper.Config{
|
||||
DisplayName: "test",
|
||||
@@ -143,7 +144,7 @@ func TestCommands_RegisterUserU2F(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommands_pushUserU2F(t *testing.T) {
|
||||
ctx := authz.WithRequestedDomain(authz.NewMockContext("instance1", "org1", "user1"), "example.com")
|
||||
ctx := http_util.WithRequestedHost(authz.NewMockContext("instance1", "org1", "user1"), "example.com")
|
||||
webauthnConfig := &webauthn_helper.Config{
|
||||
DisplayName: "test",
|
||||
ExternalSecure: true,
|
||||
|
Reference in New Issue
Block a user