fix: handle default org id (#3769)

This commit is contained in:
Livio Amstutz 2022-06-03 14:30:39 +02:00 committed by GitHub
parent ebb73186b6
commit 0baaaf8a05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 331 additions and 158 deletions

View File

@ -272,6 +272,30 @@ Checks whether an organisation exists by the given parameters
GET: /orgs/_is_unique GET: /orgs/_is_unique
### SetDefaultOrg
> **rpc** SetDefaultOrg([SetDefaultOrgRequest](#setdefaultorgrequest))
[SetDefaultOrgResponse](#setdefaultorgresponse)
Set the default org
PUT: /orgs/default/{org_id}
### GetDefaultOrg
> **rpc** GetDefaultOrg([GetDefaultOrgRequest](#getdefaultorgrequest))
[GetDefaultOrgResponse](#getdefaultorgresponse)
Set the default org
GET: /orgs/default
### ListOrgs ### ListOrgs
> **rpc** ListOrgs([ListOrgsRequest](#listorgsrequest)) > **rpc** ListOrgs([ListOrgsRequest](#listorgsrequest))
@ -1964,6 +1988,23 @@ This is an empty request
### GetDefaultOrgRequest
This is an empty request
### GetDefaultOrgResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| org | zitadel.org.v1.Org | - | |
### GetDefaultPasswordResetMessageTextRequest ### GetDefaultPasswordResetMessageTextRequest
@ -3256,6 +3297,28 @@ This is an empty request
### SetDefaultOrgRequest
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| org_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
### SetDefaultOrgResponse
| Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- |
| details | zitadel.v1.ObjectDetails | - | |
### SetDefaultPasswordResetMessageTextRequest ### SetDefaultPasswordResetMessageTextRequest

View File

@ -4701,8 +4701,9 @@ This is an empty request
| Field | Type | Description | Validation | | Field | Type | Description | Validation |
| ----- | ---- | ----------- | ----------- | | ----- | ---- | ----------- | ----------- |
| global_org_id | string | - | | | global_org_id | string | deprecated: use default_org_id instead | |
| iam_project_id | string | - | | | iam_project_id | string | - | |
| default_org_id | string | - | |

View File

@ -18,6 +18,7 @@ type Instance interface {
RequestedDomain() string RequestedDomain() string
RequestedHost() string RequestedHost() string
DefaultLanguage() language.Tag DefaultLanguage() language.Tag
DefaultOrganisationID() string
} }
type InstanceVerifier interface { type InstanceVerifier interface {
@ -25,15 +26,16 @@ type InstanceVerifier interface {
} }
type instance struct { type instance struct {
ID string id string
Domain string domain string
projectID string projectID string
appID string appID string
clientID string clientID string
orgID string
} }
func (i *instance) InstanceID() string { func (i *instance) InstanceID() string {
return i.ID return i.id
} }
func (i *instance) ProjectID() string { func (i *instance) ProjectID() string {
@ -49,17 +51,21 @@ func (i *instance) ConsoleApplicationID() string {
} }
func (i *instance) RequestedDomain() string { func (i *instance) RequestedDomain() string {
return i.Domain return i.domain
} }
func (i *instance) RequestedHost() string { func (i *instance) RequestedHost() string {
return i.Domain return i.domain
} }
func (i *instance) DefaultLanguage() language.Tag { func (i *instance) DefaultLanguage() language.Tag {
return language.Und return language.Und
} }
func (i *instance) DefaultOrganisationID() string {
return i.orgID
}
func GetInstance(ctx context.Context) Instance { func GetInstance(ctx context.Context) Instance {
instance, ok := ctx.Value(instanceKey).(Instance) instance, ok := ctx.Value(instanceKey).(Instance)
if !ok { if !ok {
@ -73,7 +79,7 @@ func WithInstance(ctx context.Context, instance Instance) context.Context {
} }
func WithInstanceID(ctx context.Context, id string) context.Context { func WithInstanceID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, instanceKey, &instance{ID: id}) return context.WithValue(ctx, instanceKey, &instance{id: id})
} }
func WithRequestedDomain(ctx context.Context, domain string) context.Context { func WithRequestedDomain(ctx context.Context, domain string) context.Context {
@ -82,7 +88,7 @@ func WithRequestedDomain(ctx context.Context, domain string) context.Context {
i = new(instance) i = new(instance)
} }
i.Domain = domain i.domain = domain
return context.WithValue(ctx, instanceKey, i) return context.WithValue(ctx, instanceKey, i)
} }

View File

@ -88,6 +88,10 @@ func (m *mockInstance) DefaultLanguage() language.Tag {
return language.English return language.English
} }
func (m *mockInstance) DefaultOrganisationID() string {
return "orgID"
}
func (m *mockInstance) RequestedDomain() string { func (m *mockInstance) RequestedDomain() string {
return "zitadel.cloud" return "zitadel.cloud"
} }

View File

@ -17,6 +17,21 @@ func (s *Server) IsOrgUnique(ctx context.Context, req *admin_pb.IsOrgUniqueReque
return &admin_pb.IsOrgUniqueResponse{IsUnique: isUnique}, err return &admin_pb.IsOrgUniqueResponse{IsUnique: isUnique}, err
} }
func (s *Server) SetDefaultOrg(ctx context.Context, req *admin_pb.SetDefaultOrgRequest) (*admin_pb.SetDefaultOrgResponse, error) {
details, err := s.command.SetDefaultOrg(ctx, req.OrgId)
if err != nil {
return nil, err
}
return &admin_pb.SetDefaultOrgResponse{
Details: object.DomainToChangeDetailsPb(details),
}, nil
}
func (s *Server) GetDefaultOrg(ctx context.Context, _ *admin_pb.GetDefaultOrgRequest) (*admin_pb.GetDefaultOrgResponse, error) {
org, err := s.query.OrgByID(ctx, authz.GetInstance(ctx).DefaultOrganisationID())
return &admin_pb.GetDefaultOrgResponse{Org: org_grpc.OrgToPb(org)}, err
}
func (s *Server) GetOrgByID(ctx context.Context, req *admin_pb.GetOrgByIDRequest) (*admin_pb.GetOrgByIDResponse, error) { func (s *Server) GetOrgByID(ctx context.Context, req *admin_pb.GetOrgByIDRequest) (*admin_pb.GetOrgByIDResponse, error) {
org, err := s.query.OrgByID(ctx, req.Id) org, err := s.query.OrgByID(ctx, req.Id)
if err != nil { if err != nil {

View File

@ -12,7 +12,8 @@ func (s *Server) GetIAM(ctx context.Context, _ *mgmt_pb.GetIAMRequest) (*mgmt_pb
return nil, err return nil, err
} }
return &mgmt_pb.GetIAMResponse{ return &mgmt_pb.GetIAMResponse{
GlobalOrgId: iam.GlobalOrgID, GlobalOrgId: iam.DefaultOrgID,
DefaultOrgId: iam.DefaultOrgID,
IamProjectId: iam.IAMProjectID, IamProjectId: iam.IAMProjectID,
}, nil }, nil
} }

View File

@ -213,7 +213,7 @@ func (s *Server) ListOrgMemberRoles(ctx context.Context, _ *mgmt_pb.ListOrgMembe
if err != nil { if err != nil {
return nil, err return nil, err
} }
roles := s.query.GetOrgMemberRoles(authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID) roles := s.query.GetOrgMemberRoles(authz.GetCtxData(ctx).OrgID == iam.DefaultOrgID)
return &mgmt_pb.ListOrgMemberRolesResponse{ return &mgmt_pb.ListOrgMemberRolesResponse{
Result: roles, Result: roles,
}, nil }, nil

View File

@ -182,6 +182,10 @@ func (m *mockInstance) DefaultLanguage() language.Tag {
return language.English return language.English
} }
func (m *mockInstance) DefaultOrganisationID() string {
return "orgID"
}
func (m *mockInstance) RequestedDomain() string { func (m *mockInstance) RequestedDomain() string {
return "localhost" return "localhost"
} }

View File

@ -266,6 +266,10 @@ func (m *mockInstance) DefaultLanguage() language.Tag {
return language.English return language.English
} }
func (m *mockInstance) DefaultOrganisationID() string {
return "orgID"
}
func (m *mockInstance) RequestedDomain() string { func (m *mockInstance) RequestedDomain() string {
return "zitadel.cloud" return "zitadel.cloud"
} }

View File

@ -16,12 +16,9 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte
if resourceOwner == "" { if resourceOwner == "" {
resourceOwner = config.AggregateID resourceOwner = config.AggregateID
} }
if resourceOwner == authz.GetInstance(ctx).InstanceID() { instance := authz.GetInstance(ctx)
iam, err := l.query.Instance(ctx) if resourceOwner == instance.InstanceID() {
if err != nil { resourceOwner = instance.DefaultOrganisationID()
return nil, err
}
resourceOwner = iam.GlobalOrgID
} }
triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner) triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner)
if err != nil { if err != nil {

View File

@ -12,6 +12,7 @@ import (
"github.com/zitadel/oidc/v2/pkg/oidc" "github.com/zitadel/oidc/v2/pkg/oidc"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/zitadel/zitadel/internal/api/authz"
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@ -204,32 +205,26 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
err = nil err = nil
} }
iam, err := l.query.Instance(r.Context()) resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err)
return
}
resourceOwner := iam.GlobalOrgID if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner {
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID {
resourceOwner = authReq.RequestedOrgID resourceOwner = authReq.RequestedOrgID
} }
orgIAMPolicy, err := l.getOrgDomainPolicy(r, resourceOwner) orgIAMPolicy, err := l.getOrgDomainPolicy(r, resourceOwner)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
return return
} }
human, idpLinking, _ := l.mapExternalUserToLoginUser(orgIAMPolicy, externalUser, idpConfig) human, idpLinking, _ := l.mapExternalUserToLoginUser(orgIAMPolicy, externalUser, idpConfig)
if !idpConfig.AutoRegister { if !idpConfig.AutoRegister {
l.renderExternalNotFoundOption(w, r, authReq, iam, orgIAMPolicy, human, idpLinking, err) l.renderExternalNotFoundOption(w, r, authReq, orgIAMPolicy, human, idpLinking, err)
return return
} }
authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, userAgentID) authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, userAgentID)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, iam, orgIAMPolicy, human, idpLinking, err) l.renderExternalNotFoundOption(w, r, authReq, orgIAMPolicy, human, idpLinking, err)
return return
} }
l.handleAutoRegister(w, r, authReq) l.handleAutoRegister(w, r, authReq)
@ -249,20 +244,15 @@ func (l *Login) handleExternalUserAuthenticated(w http.ResponseWriter, r *http.R
l.renderNextStep(w, r, authReq) l.renderNextStep(w, r, authReq)
} }
func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *query.Instance, orgIAMPolicy *query.DomainPolicy, human *domain.Human, externalIDP *domain.UserIDPLink, err error) { func (l *Login) renderExternalNotFoundOption(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, orgIAMPolicy *query.DomainPolicy, human *domain.Human, externalIDP *domain.UserIDPLink, err error) {
var errID, errMessage string var errID, errMessage string
if err != nil { if err != nil {
errID, errMessage = l.getErrorMessage(r, err) errID, errMessage = l.getErrorMessage(r, err)
} }
if orgIAMPolicy == nil { if orgIAMPolicy == nil {
iam, err = l.query.Instance(r.Context()) resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil {
l.renderError(w, r, authReq, err)
return
}
resourceOwner := iam.GlobalOrgID
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID { if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner {
resourceOwner = authReq.RequestedOrgID resourceOwner = authReq.RequestedOrgID
} }
@ -317,7 +307,7 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http
data := new(externalNotFoundOptionFormData) data := new(externalNotFoundOptionFormData)
authReq, err := l.getAuthRequestAndParseData(r, data) authReq, err := l.getAuthRequestAndParseData(r, data)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
return return
} }
if data.Link { if data.Link {
@ -327,7 +317,7 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context()) userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.ResetLinkingUsers(r.Context(), authReq.ID, userAgentID) err = l.authRepo.ResetLinkingUsers(r.Context(), authReq.ID, userAgentID)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
} }
l.handleLogin(w, r) l.handleLogin(w, r)
return return
@ -336,29 +326,23 @@ func (l *Login) handleExternalNotFoundOptionCheck(w http.ResponseWriter, r *http
} }
func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) { func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
iam, err := l.query.Instance(r.Context()) resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err)
return
}
resourceOwner := iam.GlobalOrgID
memberRoles := []string{domain.RoleSelfManagementGlobal} memberRoles := []string{domain.RoleSelfManagementGlobal}
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID { if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner {
memberRoles = nil memberRoles = nil
resourceOwner = authReq.RequestedOrgID resourceOwner = authReq.RequestedOrgID
} }
orgIamPolicy, err := l.getOrgDomainPolicy(r, resourceOwner) orgIamPolicy, err := l.getOrgDomainPolicy(r, resourceOwner)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
return return
} }
idpConfig, err := l.authRepo.GetIDPConfigByID(r.Context(), authReq.SelectedIDPConfigID) idpConfig, err := l.authRepo.GetIDPConfigByID(r.Context(), authReq.SelectedIDPConfigID)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, iam, orgIamPolicy, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, orgIamPolicy, nil, nil, err)
return return
} }
@ -371,12 +355,12 @@ func (l *Login) handleAutoRegister(w http.ResponseWriter, r *http.Request, authR
user, externalIDP, metadata := l.mapExternalUserToLoginUser(orgIamPolicy, linkingUser, idpConfig) user, externalIDP, metadata := l.mapExternalUserToLoginUser(orgIamPolicy, linkingUser, idpConfig)
user, metadata, err = l.customExternalUserToLoginUserMapping(user, nil, authReq, idpConfig, metadata, resourceOwner) user, metadata, err = l.customExternalUserToLoginUserMapping(user, nil, authReq, idpConfig, metadata, resourceOwner)
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, iam, orgIamPolicy, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, orgIamPolicy, nil, nil, err)
return return
} }
err = l.authRepo.AutoRegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, memberRoles, authReq.ID, userAgentID, resourceOwner, metadata, domain.BrowserInfoFromRequest(r)) err = l.authRepo.AutoRegisterExternalUser(setContext(r.Context(), resourceOwner), user, externalIDP, memberRoles, authReq.ID, userAgentID, resourceOwner, metadata, domain.BrowserInfoFromRequest(r))
if err != nil { if err != nil {
l.renderExternalNotFoundOption(w, r, authReq, iam, orgIamPolicy, user, externalIDP, err) l.renderExternalNotFoundOption(w, r, authReq, orgIamPolicy, user, externalIDP, err)
return return
} }
authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID) authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID)

View File

@ -8,6 +8,7 @@ import (
"github.com/zitadel/oidc/v2/pkg/oidc" "github.com/zitadel/oidc/v2/pkg/oidc"
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
iam_model "github.com/zitadel/zitadel/internal/iam/model" iam_model "github.com/zitadel/zitadel/internal/iam/model"
@ -111,12 +112,7 @@ func (l *Login) handleExternalRegisterCallback(w http.ResponseWriter, r *http.Re
} }
func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) { func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, idpConfig *iam_model.IDPConfigView, userAgentID string, tokens *oidc.Tokens) {
iam, err := l.query.Instance(r.Context()) resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
resourceOwner := iam.GlobalOrgID
if authReq.RequestedOrgID != "" { if authReq.RequestedOrgID != "" {
resourceOwner = authReq.RequestedOrgID resourceOwner = authReq.RequestedOrgID
} }
@ -134,11 +130,11 @@ func (l *Login) handleExternalUserRegister(w http.ResponseWriter, r *http.Reques
l.renderExternalRegisterOverview(w, r, authReq, orgIamPolicy, user, externalIDP, nil) l.renderExternalRegisterOverview(w, r, authReq, orgIamPolicy, user, externalIDP, nil)
return return
} }
l.registerExternalUser(w, r, authReq, iam, user, externalIDP) l.registerExternalUser(w, r, authReq, user, externalIDP)
} }
func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, iam *query.Instance, user *domain.Human, externalIDP *domain.UserIDPLink) { func (l *Login) registerExternalUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, user *domain.Human, externalIDP *domain.UserIDPLink) {
resourceOwner := iam.GlobalOrgID resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
memberRoles := []string{domain.RoleSelfManagementGlobal} memberRoles := []string{domain.RoleSelfManagementGlobal}
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner { if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner {
@ -204,15 +200,10 @@ func (l *Login) handleExternalRegisterCheck(w http.ResponseWriter, r *http.Reque
return return
} }
iam, err := l.query.Instance(r.Context()) resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil {
l.renderRegisterOption(w, r, authReq, err)
return
}
resourceOwner := iam.GlobalOrgID
memberRoles := []string{domain.RoleSelfManagementGlobal} memberRoles := []string{domain.RoleSelfManagementGlobal}
if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != iam.GlobalOrgID { if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner {
memberRoles = nil memberRoles = nil
resourceOwner = authReq.RequestedOrgID resourceOwner = authReq.RequestedOrgID
} }

View File

@ -112,7 +112,7 @@ func (l *Login) jwtExtractionUserNotFound(w http.ResponseWriter, r *http.Request
err = nil err = nil
} }
if !idpConfig.AutoRegister { if !idpConfig.AutoRegister {
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
return return
} }
authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID) authReq, err = l.authRepo.AuthRequestByID(r.Context(), authReq.ID, authReq.AgentID)

View File

@ -98,10 +98,13 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *dom
data := l.getUserData(r, authReq, "Login", errID, errMessage) data := l.getUserData(r, authReq, "Login", errID, errMessage)
funcs := map[string]interface{}{ funcs := map[string]interface{}{
"hasUsernamePasswordLogin": func() bool { "hasUsernamePasswordLogin": func() bool {
return authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowUsernamePassword return authReq != nil && authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowUsernamePassword
}, },
"hasExternalLogin": func() bool { "hasExternalLogin": func() bool {
return authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0 return authReq != nil && authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowExternalIDP && authReq.AllowedExternalIDPs != nil && len(authReq.AllowedExternalIDPs) > 0
},
"hasRegistration": func() bool {
return authReq != nil && authReq.LoginPolicy != nil && authReq.LoginPolicy.AllowRegister
}, },
} }
l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplLogin], data, funcs) l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplLogin], data, funcs)

View File

@ -5,6 +5,7 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors" caos_errs "github.com/zitadel/zitadel/internal/errors"
@ -61,16 +62,11 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
l.renderRegister(w, r, authRequest, data, err) l.renderRegister(w, r, authRequest, data, err)
return return
} }
iam, err := l.query.Instance(r.Context())
if err != nil {
l.renderRegister(w, r, authRequest, data, err)
return
}
resourceOwner := iam.GlobalOrgID resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID()
memberRoles := []string{domain.RoleSelfManagementGlobal} memberRoles := []string{domain.RoleSelfManagementGlobal}
if authRequest != nil && authRequest.RequestedOrgID != "" && authRequest.RequestedOrgID != iam.GlobalOrgID { if authRequest != nil && authRequest.RequestedOrgID != "" && authRequest.RequestedOrgID != resourceOwner {
memberRoles = nil memberRoles = nil
resourceOwner = authRequest.RequestedOrgID resourceOwner = authRequest.RequestedOrgID
} }
@ -114,10 +110,6 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
if formData.Language == "" { if formData.Language == "" {
formData.Language = l.renderer.ReqLang(translator, r).String() formData.Language = l.renderer.ReqLang(translator, r).String()
} }
data := registerData{
baseData: l.getBaseData(r, authRequest, "Register", errID, errMessage),
registerFormData: *formData,
}
var resourceOwner string var resourceOwner string
if authRequest != nil { if authRequest != nil {
@ -125,12 +117,12 @@ func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authReque
} }
if resourceOwner == "" { if resourceOwner == "" {
iam, err := l.query.Instance(r.Context()) resourceOwner = authz.GetInstance(r.Context()).DefaultOrganisationID()
if err != nil { }
l.renderRegister(w, r, authRequest, formData, err)
return data := registerData{
} baseData: l.getBaseData(r, authRequest, "Register", errID, errMessage),
resourceOwner = iam.GlobalOrgID registerFormData: *formData,
} }
pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, authRequest, resourceOwner) pwPolicy, description, _ := l.getPasswordComplexityPolicy(r, authRequest, resourceOwner)

View File

@ -211,6 +211,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
"hasExternalLogin": func() bool { "hasExternalLogin": func() bool {
return false return false
}, },
"hasRegistration": func() bool {
return true
},
"idpProviderClass": func(stylingType domain.IDPConfigStylingType) string { "idpProviderClass": func(stylingType domain.IDPConfigStylingType) string {
return stylingType.GetCSSClass() return stylingType.GetCSSClass()
}, },
@ -299,7 +302,7 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
case *domain.LinkUsersStep: case *domain.LinkUsersStep:
l.linkUsers(w, r, authReq, err) l.linkUsers(w, r, authReq, err)
case *domain.ExternalNotFoundOptionStep: case *domain.ExternalNotFoundOptionStep:
l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, nil, err) l.renderExternalNotFoundOption(w, r, authReq, nil, nil, nil, err)
case *domain.ExternalLoginStep: case *domain.ExternalLoginStep:
l.handleExternalLoginStep(w, r, authReq, step.SelectedIDPConfigID) l.handleExternalLoginStep(w, r, authReq, step.SelectedIDPConfigID)
case *domain.GrantRequiredStep: case *domain.GrantRequiredStep:
@ -346,7 +349,7 @@ func (l *Login) getBaseData(r *http.Request, authReq *domain.AuthRequest, title
PrivateLabelingOrgID: l.getPrivateLabelingID(r, authReq), PrivateLabelingOrgID: l.getPrivateLabelingID(r, authReq),
OrgID: l.getOrgID(r, authReq), OrgID: l.getOrgID(r, authReq),
OrgName: l.getOrgName(authReq), OrgName: l.getOrgName(authReq),
PrimaryDomain: l.getOrgPrimaryDomain(authReq), PrimaryDomain: l.getOrgPrimaryDomain(r, authReq),
DisplayLoginNameSuffix: l.isDisplayLoginNameSuffix(authReq), DisplayLoginNameSuffix: l.isDisplayLoginNameSuffix(authReq),
AuthReqID: getRequestID(authReq, r), AuthReqID: getRequestID(authReq, r),
CSRF: csrf.TemplateField(r), CSRF: csrf.TemplateField(r),
@ -490,11 +493,17 @@ func (l *Login) getOrgName(authReq *domain.AuthRequest) string {
return authReq.RequestedOrgName return authReq.RequestedOrgName
} }
func (l *Login) getOrgPrimaryDomain(authReq *domain.AuthRequest) string { func (l *Login) getOrgPrimaryDomain(r *http.Request, authReq *domain.AuthRequest) string {
if authReq == nil { orgID := authz.GetInstance(r.Context()).DefaultOrganisationID()
if authReq != nil && authReq.RequestedPrimaryDomain != "" {
return authReq.RequestedPrimaryDomain
}
org, err := l.query.OrgByID(r.Context(), orgID)
if err != nil {
logging.New().WithError(err).Error("cannot get default org")
return "" return ""
} }
return authReq.RequestedPrimaryDomain return org.Domain
} }
func (l *Login) isDisplayLoginNameSuffix(authReq *domain.AuthRequest) bool { func (l *Login) isDisplayLoginNameSuffix(authReq *domain.AuthRequest) bool {

View File

@ -39,7 +39,7 @@
<div class="lgn-suffix-wrapper"> <div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" <input class="lgn-input lgn-suffix-input" type="text" id="username" name="username"
value="{{ .Username }}" required> value="{{ .Username }}" required>
{{if .DisplayLoginNameSuffix}} {{if .ShowUsername}}
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span> <span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
{{end}} {{end}}
</div> </div>

View File

@ -39,7 +39,7 @@
<div class="lgn-suffix-wrapper"> <div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" <input class="lgn-input lgn-suffix-input" type="text" id="username" name="username"
value="{{ .Username }}" required> value="{{ .Username }}" required>
{{if .DisplayLoginNameSuffix}} {{if .ShowUsername}}
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span> <span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
{{end}} {{end}}
</div> </div>

View File

@ -35,7 +35,7 @@
<div class="lgn-actions lgn-reverse-order"> <div class="lgn-actions lgn-reverse-order">
<button class="lgn-raised-button lgn-primary lgn-initial-focus" id="submit-button" type="submit">{{t "Login.NextButtonText"}}</button> <button class="lgn-raised-button lgn-primary lgn-initial-focus" id="submit-button" type="submit">{{t "Login.NextButtonText"}}</button>
<span class="fill-space"></span> <span class="fill-space"></span>
{{if .LoginPolicy.AllowRegister}} {{if hasRegistration}}
<button class="lgn-stroked-button" name="register" value="true" formnovalidate>{{t "Login.RegisterButtonText"}}</button> <button class="lgn-stroked-button" name="register" value="true" formnovalidate>{{t "Login.RegisterButtonText"}}</button>
{{end}} {{end}}
</div> </div>
@ -60,4 +60,4 @@
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script> <script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
<script src="{{ resourceUrl "scripts/input_suffix_offset.js" }}"></script> <script src="{{ resourceUrl "scripts/input_suffix_offset.js" }}"></script>
{{template "main-bottom" .}} {{template "main-bottom" .}}

View File

@ -42,7 +42,7 @@
<label class="lgn-label" for="username">{{t "RegistrationUser.UsernameLabel"}}</label> <label class="lgn-label" for="username">{{t "RegistrationUser.UsernameLabel"}}</label>
<div class="lgn-suffix-wrapper"> <div class="lgn-suffix-wrapper">
<input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required> <input class="lgn-input lgn-suffix-input" type="text" id="username" name="username" autocomplete="email" value="{{ .Email }}" required>
{{if .DisplayLoginNameSuffix}} {{if .ShowUsername}}
<span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span> <span id="default-login-suffix" lgnsuffix class="loginname-suffix">@{{.PrimaryDomain}}</span>
{{end}} {{end}}
</div> </div>

View File

@ -114,7 +114,7 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil { if err != nil {
return err return err
} }
idp, err = i.view.IDPConfigByID(idp.IDPConfigID, idp.InstanceID) idp, err = i.view.IDPConfigByID(idp.IDPConfigID, event.InstanceID)
if err != nil { if err != nil {
return err return err
} }
@ -125,7 +125,7 @@ func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil { if err != nil {
return err return err
} }
idp, err = i.view.IDPConfigByID(idp.IDPConfigID, idp.InstanceID) idp, err = i.view.IDPConfigByID(idp.IDPConfigID, event.InstanceID)
if err != nil { if err != nil {
return err return err
} }

View File

@ -272,6 +272,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (str
validations = append(validations, validations = append(validations,
AddOrgCommand(ctx, orgAgg, setup.Org.Name), AddOrgCommand(ctx, orgAgg, setup.Org.Name),
c.prepareSetDefaultOrg(instanceAgg, orgAgg.ID),
AddHumanCommand(userAgg, &setup.Org.Human, c.userPasswordAlg, c.userEncryption), AddHumanCommand(userAgg, &setup.Org.Human, c.userPasswordAlg, c.userEncryption),
c.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner), c.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner),
c.AddInstanceMemberCommand(instanceAgg, userID, domain.RoleIAMOwner), c.AddInstanceMemberCommand(instanceAgg, userID, domain.RoleIAMOwner),
@ -379,6 +380,24 @@ func (c *Commands) SetDefaultLanguage(ctx context.Context, defaultLanguage langu
}, nil }, nil
} }
func (c *Commands) SetDefaultOrg(ctx context.Context, orgID string) (*domain.ObjectDetails, error) {
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
validation := c.prepareSetDefaultOrg(instanceAgg, orgID)
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation)
if err != nil {
return nil, err
}
events, err := c.eventstore.Push(ctx, cmds...)
if err != nil {
return nil, err
}
return &domain.ObjectDetails{
Sequence: events[len(events)-1].Sequence(),
EventDate: events[len(events)-1].CreationDate(),
ResourceOwner: events[len(events)-1].Aggregate().InstanceID,
}, nil
}
func prepareAddInstance(a *instance.Aggregate, instanceName string, defaultLanguage language.Tag) preparation.Validation { func prepareAddInstance(a *instance.Aggregate, instanceName string, defaultLanguage language.Tag) preparation.Validation {
return func() (preparation.CreateCommands, error) { return func() (preparation.CreateCommands, error) {
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
@ -412,15 +431,25 @@ func SetIAMConsoleID(a *instance.Aggregate, clientID, appID *string) preparation
} }
} }
func (c *Commands) setGlobalOrg(ctx context.Context, iamAgg *eventstore.Aggregate, iamWriteModel *InstanceWriteModel, orgID string) (eventstore.Command, error) { func (c *Commands) prepareSetDefaultOrg(a *instance.Aggregate, orgID string) preparation.Validation {
err := c.eventstore.FilterToQueryReducer(ctx, iamWriteModel) return func() (preparation.CreateCommands, error) {
if err != nil { if orgID == "" {
return nil, err return nil, errors.ThrowInvalidArgument(nil, "INST-SWffe", "Errors.Invalid.Argument")
}
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
writeModel, err := getInstanceWriteModel(ctx, filter)
if err != nil {
return nil, err
}
if writeModel.DefaultOrgID == orgID {
return nil, errors.ThrowPreconditionFailed(nil, "INST-SDfw2", "Errors.Instance.NotChanged")
}
if exists, err := ExistsOrg(ctx, filter, orgID); err != nil || !exists {
return nil, errors.ThrowPreconditionFailed(err, "INSTA-Wfe21", "Errors.Org.NotFound")
}
return []eventstore.Command{instance.NewDefaultOrgSetEventEvent(ctx, &a.Aggregate, orgID)}, nil
}, nil
} }
if iamWriteModel.GlobalOrgID != "" {
return nil, errors.ThrowPreconditionFailed(nil, "IAM-HGG24", "Errors.IAM.GlobalOrgAlreadySet")
}
return instance.NewGlobalOrgSetEventEvent(ctx, iamAgg, orgID), nil
} }
func (c *Commands) setIAMProject(ctx context.Context, iamAgg *eventstore.Aggregate, iamWriteModel *InstanceWriteModel, projectID string) (eventstore.Command, error) { func (c *Commands) setIAMProject(ctx context.Context, iamAgg *eventstore.Aggregate, iamWriteModel *InstanceWriteModel, projectID string) (eventstore.Command, error) {

View File

@ -15,7 +15,7 @@ type InstanceWriteModel struct {
State domain.InstanceState State domain.InstanceState
GeneratedDomain string GeneratedDomain string
GlobalOrgID string DefaultOrgID string
ProjectID string ProjectID string
DefaultLanguage language.Tag DefaultLanguage language.Tag
} }
@ -46,8 +46,8 @@ func (wm *InstanceWriteModel) Reduce() error {
wm.GeneratedDomain = e.Domain wm.GeneratedDomain = e.Domain
case *instance.ProjectSetEvent: case *instance.ProjectSetEvent:
wm.ProjectID = e.ProjectID wm.ProjectID = e.ProjectID
case *instance.GlobalOrgSetEvent: case *instance.DefaultOrgSetEvent:
wm.GlobalOrgID = e.OrgID wm.DefaultOrgID = e.OrgID
case *instance.DefaultLanguageSetEvent: case *instance.DefaultLanguageSetEvent:
wm.DefaultLanguage = e.Language wm.DefaultLanguage = e.Language
} }
@ -68,7 +68,7 @@ func (wm *InstanceWriteModel) Query() *eventstore.SearchQueryBuilder {
instance.InstanceDomainAddedEventType, instance.InstanceDomainAddedEventType,
instance.InstanceDomainRemovedEventType, instance.InstanceDomainRemovedEventType,
instance.ProjectSetEventType, instance.ProjectSetEventType,
instance.GlobalOrgSetEventType, instance.DefaultOrgSetEventType,
instance.DefaultLanguageSetEventType). instance.DefaultLanguageSetEventType).
Builder() Builder()
} }

View File

@ -233,6 +233,10 @@ func (m *mockInstance) DefaultLanguage() language.Tag {
return language.English return language.English
} }
func (m *mockInstance) DefaultOrganisationID() string {
return "orgID"
}
func (m *mockInstance) RequestedDomain() string { func (m *mockInstance) RequestedDomain() string {
return "zitadel.cloud" return "zitadel.cloud"
} }

View File

@ -211,6 +211,35 @@ func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.Obj
return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil
} }
func ExistsOrg(ctx context.Context, filter preparation.FilterToQueryReducer, id string) (exists bool, err error) {
events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
ResourceOwner(id).
OrderAsc().
AddQuery().
AggregateTypes(org.AggregateType).
AggregateIDs(id).
EventTypes(
org.OrgAddedEventType,
org.OrgDeactivatedEventType,
org.OrgReactivatedEventType,
org.OrgRemovedEventType,
).Builder())
if err != nil {
return false, err
}
for _, event := range events {
switch event.(type) {
case *org.OrgAddedEvent, *org.OrgReactivatedEvent:
exists = true
case *org.OrgDeactivatedEvent, *org.OrgRemovedEvent:
exists = false
}
}
return exists, nil
}
func (c *Commands) setUpOrg( func (c *Commands) setUpOrg(
ctx context.Context, ctx context.Context,
organisation *domain.Org, organisation *domain.Org,

View File

@ -24,7 +24,7 @@ const (
type IAM struct { type IAM struct {
es_models.ObjectRoot es_models.ObjectRoot
GlobalOrgID string DefaultOrgID string
IAMProjectID string IAMProjectID string
SetUpDone domain.Step SetUpDone domain.Step
SetUpStarted domain.Step SetUpStarted domain.Step

View File

@ -39,8 +39,8 @@ var (
name: projection.InstanceColumnSequence, name: projection.InstanceColumnSequence,
table: instanceTable, table: instanceTable,
} }
InstanceColumnGlobalOrgID = Column{ InstanceColumnDefaultOrgID = Column{
name: projection.InstanceColumnGlobalOrgID, name: projection.InstanceColumnDefaultOrgID,
table: instanceTable, table: instanceTable,
} }
InstanceColumnProjectID = Column{ InstanceColumnProjectID = Column{
@ -68,7 +68,7 @@ type Instance struct {
Sequence uint64 Sequence uint64
Name string Name string
GlobalOrgID string DefaultOrgID string
IAMProjectID string IAMProjectID string
ConsoleID string ConsoleID string
ConsoleAppID string ConsoleAppID string
@ -110,6 +110,10 @@ func (i *Instance) DefaultLanguage() language.Tag {
return i.DefaultLang return i.DefaultLang
} }
func (i *Instance) DefaultOrganisationID() string {
return i.DefaultOrgID
}
type InstanceSearchQueries struct { type InstanceSearchQueries struct {
SearchRequest SearchRequest
Queries []SearchQuery Queries []SearchQuery
@ -196,7 +200,7 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
InstanceColumnCreationDate.identifier(), InstanceColumnCreationDate.identifier(),
InstanceColumnChangeDate.identifier(), InstanceColumnChangeDate.identifier(),
InstanceColumnSequence.identifier(), InstanceColumnSequence.identifier(),
InstanceColumnGlobalOrgID.identifier(), InstanceColumnDefaultOrgID.identifier(),
InstanceColumnProjectID.identifier(), InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(), InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(), InstanceColumnConsoleAppID.identifier(),
@ -211,7 +215,7 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
&instance.CreationDate, &instance.CreationDate,
&instance.ChangeDate, &instance.ChangeDate,
&instance.Sequence, &instance.Sequence,
&instance.GlobalOrgID, &instance.DefaultOrgID,
&instance.IAMProjectID, &instance.IAMProjectID,
&instance.ConsoleID, &instance.ConsoleID,
&instance.ConsoleAppID, &instance.ConsoleAppID,
@ -235,7 +239,7 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
InstanceColumnChangeDate.identifier(), InstanceColumnChangeDate.identifier(),
InstanceColumnSequence.identifier(), InstanceColumnSequence.identifier(),
InstanceColumnName.identifier(), InstanceColumnName.identifier(),
InstanceColumnGlobalOrgID.identifier(), InstanceColumnDefaultOrgID.identifier(),
InstanceColumnProjectID.identifier(), InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(), InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(), InstanceColumnConsoleAppID.identifier(),
@ -254,7 +258,7 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
&instance.ChangeDate, &instance.ChangeDate,
&instance.Sequence, &instance.Sequence,
&instance.Name, &instance.Name,
&instance.GlobalOrgID, &instance.DefaultOrgID,
&instance.IAMProjectID, &instance.IAMProjectID,
&instance.ConsoleID, &instance.ConsoleID,
&instance.ConsoleAppID, &instance.ConsoleAppID,
@ -288,7 +292,7 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
InstanceColumnChangeDate.identifier(), InstanceColumnChangeDate.identifier(),
InstanceColumnSequence.identifier(), InstanceColumnSequence.identifier(),
InstanceColumnName.identifier(), InstanceColumnName.identifier(),
InstanceColumnGlobalOrgID.identifier(), InstanceColumnDefaultOrgID.identifier(),
InstanceColumnProjectID.identifier(), InstanceColumnProjectID.identifier(),
InstanceColumnConsoleID.identifier(), InstanceColumnConsoleID.identifier(),
InstanceColumnConsoleAppID.identifier(), InstanceColumnConsoleAppID.identifier(),
@ -324,7 +328,7 @@ func prepareInstanceDomainQuery(host string) (sq.SelectBuilder, func(*sql.Rows)
&instance.ChangeDate, &instance.ChangeDate,
&instance.Sequence, &instance.Sequence,
&instance.Name, &instance.Name,
&instance.GlobalOrgID, &instance.DefaultOrgID,
&instance.IAMProjectID, &instance.IAMProjectID,
&instance.ConsoleID, &instance.ConsoleID,
&instance.ConsoleAppID, &instance.ConsoleAppID,

View File

@ -36,7 +36,7 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.creation_date,`+ ` projections.instances.creation_date,`+
` projections.instances.change_date,`+ ` projections.instances.change_date,`+
` projections.instances.sequence,`+ ` projections.instances.sequence,`+
` projections.instances.global_org_id,`+ ` projections.instances.default_org_id,`+
` projections.instances.iam_project_id,`+ ` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+ ` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+ ` projections.instances.console_app_id,`+
@ -65,7 +65,7 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.creation_date,`+ ` projections.instances.creation_date,`+
` projections.instances.change_date,`+ ` projections.instances.change_date,`+
` projections.instances.sequence,`+ ` projections.instances.sequence,`+
` projections.instances.global_org_id,`+ ` projections.instances.default_org_id,`+
` projections.instances.iam_project_id,`+ ` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+ ` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+ ` projections.instances.console_app_id,`+
@ -76,7 +76,7 @@ func Test_InstancePrepares(t *testing.T) {
"creation_date", "creation_date",
"change_date", "change_date",
"sequence", "sequence",
"global_org_id", "default_org_id",
"iam_project_id", "iam_project_id",
"console_client_id", "console_client_id",
"console_app_id", "console_app_id",
@ -100,7 +100,7 @@ func Test_InstancePrepares(t *testing.T) {
CreationDate: testNow, CreationDate: testNow,
ChangeDate: testNow, ChangeDate: testNow,
Sequence: 20211108, Sequence: 20211108,
GlobalOrgID: "global-org-id", DefaultOrgID: "global-org-id",
IAMProjectID: "project-id", IAMProjectID: "project-id",
ConsoleID: "client-id", ConsoleID: "client-id",
ConsoleAppID: "app-id", ConsoleAppID: "app-id",
@ -118,7 +118,7 @@ func Test_InstancePrepares(t *testing.T) {
` projections.instances.creation_date,`+ ` projections.instances.creation_date,`+
` projections.instances.change_date,`+ ` projections.instances.change_date,`+
` projections.instances.sequence,`+ ` projections.instances.sequence,`+
` projections.instances.global_org_id,`+ ` projections.instances.default_org_id,`+
` projections.instances.iam_project_id,`+ ` projections.instances.iam_project_id,`+
` projections.instances.console_client_id,`+ ` projections.instances.console_client_id,`+
` projections.instances.console_app_id,`+ ` projections.instances.console_app_id,`+

View File

@ -37,7 +37,7 @@ func (q *Queries) GetProjectMemberRoles(ctx context.Context) ([]string, error) {
return nil, err return nil, err
} }
roles := make([]string, 0) roles := make([]string, 0)
global := authz.GetCtxData(ctx).OrgID == iam.GlobalOrgID global := authz.GetCtxData(ctx).OrgID == iam.DefaultOrgID
for _, roleMap := range q.zitadelRoles { for _, roleMap := range q.zitadelRoles {
if strings.HasPrefix(roleMap.Role, "PROJECT") && !strings.HasPrefix(roleMap.Role, "PROJECT_GRANT") { if strings.HasPrefix(roleMap.Role, "PROJECT") && !strings.HasPrefix(roleMap.Role, "PROJECT_GRANT") {
if global && !strings.HasSuffix(roleMap.Role, "GLOBAL") { if global && !strings.HasSuffix(roleMap.Role, "GLOBAL") {

View File

@ -17,7 +17,7 @@ const (
InstanceColumnName = "name" InstanceColumnName = "name"
InstanceColumnChangeDate = "change_date" InstanceColumnChangeDate = "change_date"
InstanceColumnCreationDate = "creation_date" InstanceColumnCreationDate = "creation_date"
InstanceColumnGlobalOrgID = "global_org_id" InstanceColumnDefaultOrgID = "default_org_id"
InstanceColumnProjectID = "iam_project_id" InstanceColumnProjectID = "iam_project_id"
InstanceColumnConsoleID = "console_client_id" InstanceColumnConsoleID = "console_client_id"
InstanceColumnConsoleAppID = "console_app_id" InstanceColumnConsoleAppID = "console_app_id"
@ -39,7 +39,7 @@ func NewInstanceProjection(ctx context.Context, config crdb.StatementHandlerConf
crdb.NewColumn(InstanceColumnName, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnName, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnChangeDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(InstanceColumnChangeDate, crdb.ColumnTypeTimestamp),
crdb.NewColumn(InstanceColumnCreationDate, crdb.ColumnTypeTimestamp), crdb.NewColumn(InstanceColumnCreationDate, crdb.ColumnTypeTimestamp),
crdb.NewColumn(InstanceColumnGlobalOrgID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnDefaultOrgID, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnProjectID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnProjectID, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")),
crdb.NewColumn(InstanceColumnConsoleAppID, crdb.ColumnTypeText, crdb.Default("")), crdb.NewColumn(InstanceColumnConsoleAppID, crdb.ColumnTypeText, crdb.Default("")),
@ -63,8 +63,8 @@ func (p *InstanceProjection) reducers() []handler.AggregateReducer {
Reduce: p.reduceInstanceAdded, Reduce: p.reduceInstanceAdded,
}, },
{ {
Event: instance.GlobalOrgSetEventType, Event: instance.DefaultOrgSetEventType,
Reduce: p.reduceGlobalOrgSet, Reduce: p.reduceDefaultOrgSet,
}, },
{ {
Event: instance.ProjectSetEventType, Event: instance.ProjectSetEventType,
@ -100,17 +100,17 @@ func (p *InstanceProjection) reduceInstanceAdded(event eventstore.Event) (*handl
), nil ), nil
} }
func (p *InstanceProjection) reduceGlobalOrgSet(event eventstore.Event) (*handler.Statement, error) { func (p *InstanceProjection) reduceDefaultOrgSet(event eventstore.Event) (*handler.Statement, error) {
e, ok := event.(*instance.GlobalOrgSetEvent) e, ok := event.(*instance.DefaultOrgSetEvent)
if !ok { if !ok {
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-2n9f2", "reduce.wrong.event.type %s", instance.GlobalOrgSetEventType) return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-2n9f2", "reduce.wrong.event.type %s", instance.DefaultOrgSetEventType)
} }
return crdb.NewUpdateStatement( return crdb.NewUpdateStatement(
e, e,
[]handler.Column{ []handler.Column{
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()), handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
handler.NewCol(InstanceColumnSequence, e.Sequence()), handler.NewCol(InstanceColumnSequence, e.Sequence()),
handler.NewCol(InstanceColumnGlobalOrgID, e.OrgID), handler.NewCol(InstanceColumnDefaultOrgID, e.OrgID),
}, },
[]handler.Condition{ []handler.Condition{
handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID), handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID),

View File

@ -51,15 +51,15 @@ func TestInstanceProjection_reduces(t *testing.T) {
}, },
}, },
{ {
name: "reduceGlobalOrgSet", name: "reduceDefaultOrgSet",
args: args{ args: args{
event: getEvent(testEvent( event: getEvent(testEvent(
repository.EventType(instance.GlobalOrgSetEventType), repository.EventType(instance.DefaultOrgSetEventType),
instance.AggregateType, instance.AggregateType,
[]byte(`{"globalOrgId": "orgid"}`), []byte(`{"orgId": "orgid"}`),
), instance.GlobalOrgSetMapper), ), instance.DefaultOrgSetMapper),
}, },
reduce: (&InstanceProjection{}).reduceGlobalOrgSet, reduce: (&InstanceProjection{}).reduceDefaultOrgSet,
want: wantReduce{ want: wantReduce{
projection: InstanceProjectionTable, projection: InstanceProjectionTable,
aggregateType: eventstore.AggregateType("instance"), aggregateType: eventstore.AggregateType("instance"),
@ -68,7 +68,7 @@ func TestInstanceProjection_reduces(t *testing.T) {
executer: &testExecuter{ executer: &testExecuter{
executions: []execution{ executions: []execution{
{ {
expectedStmt: "UPDATE projections.instances SET (change_date, sequence, global_org_id) = ($1, $2, $3) WHERE (id = $4)", expectedStmt: "UPDATE projections.instances SET (change_date, sequence, default_org_id) = ($1, $2, $3) WHERE (id = $4)",
expectedArgs: []interface{}{ expectedArgs: []interface{}{
anyArg{}, anyArg{},
uint64(15), uint64(15),

View File

@ -11,45 +11,45 @@ import (
) )
const ( const (
GlobalOrgSetEventType eventstore.EventType = "iam.global.org.set" DefaultOrgSetEventType eventstore.EventType = "instance.default.org.set"
) )
type GlobalOrgSetEvent struct { type DefaultOrgSetEvent struct {
eventstore.BaseEvent `json:"-"` eventstore.BaseEvent `json:"-"`
OrgID string `json:"globalOrgId"` OrgID string `json:"orgId"`
} }
func (e *GlobalOrgSetEvent) Data() interface{} { func (e *DefaultOrgSetEvent) Data() interface{} {
return e return e
} }
func (e *GlobalOrgSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { func (e *DefaultOrgSetEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return nil return nil
} }
func NewGlobalOrgSetEventEvent( func NewDefaultOrgSetEventEvent(
ctx context.Context, ctx context.Context,
aggregate *eventstore.Aggregate, aggregate *eventstore.Aggregate,
orgID string, orgID string,
) *GlobalOrgSetEvent { ) *DefaultOrgSetEvent {
return &GlobalOrgSetEvent{ return &DefaultOrgSetEvent{
BaseEvent: *eventstore.NewBaseEventForPush( BaseEvent: *eventstore.NewBaseEventForPush(
ctx, ctx,
aggregate, aggregate,
GlobalOrgSetEventType, DefaultOrgSetEventType,
), ),
OrgID: orgID, OrgID: orgID,
} }
} }
func GlobalOrgSetMapper(event *repository.Event) (eventstore.Event, error) { func DefaultOrgSetMapper(event *repository.Event) (eventstore.Event, error) {
e := &GlobalOrgSetEvent{ e := &DefaultOrgSetEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event), BaseEvent: *eventstore.BaseEventFromRepo(event),
} }
err := json.Unmarshal(event.Data, e) err := json.Unmarshal(event.Data, e)
if err != nil { if err != nil {
return nil, errors.ThrowInternal(err, "IAM-cdFZH", "unable to unmarshal global org set") return nil, errors.ThrowInternal(err, "IAM-cdFZH", "unable to unmarshal default org set")
} }
return e, nil return e, nil

View File

@ -5,7 +5,7 @@ import (
) )
func RegisterEventMappers(es *eventstore.Eventstore) { func RegisterEventMappers(es *eventstore.Eventstore) {
es.RegisterFilterEventMapper(GlobalOrgSetEventType, GlobalOrgSetMapper). es.RegisterFilterEventMapper(DefaultOrgSetEventType, DefaultOrgSetMapper).
RegisterFilterEventMapper(ProjectSetEventType, ProjectSetMapper). RegisterFilterEventMapper(ProjectSetEventType, ProjectSetMapper).
RegisterFilterEventMapper(ConsoleSetEventType, ConsoleSetMapper). RegisterFilterEventMapper(ConsoleSetEventType, ConsoleSetMapper).
RegisterFilterEventMapper(DefaultLanguageSetEventType, DefaultLanguageSetMapper). RegisterFilterEventMapper(DefaultLanguageSetEventType, DefaultLanguageSetMapper).

View File

@ -271,8 +271,6 @@ Errors:
MemberAlreadyExisting: Member existiert bereits MemberAlreadyExisting: Member existiert bereits
MemberNotExisting: Member existiert nicht MemberNotExisting: Member existiert nicht
IDMissing: ID fehlt IDMissing: ID fehlt
GlobalOrgMissing: Globale Organisation fehlt
GlobalOrgAlreadySet: Globale Organisation wurde bereits gesetzt
IAMProjectIDMissing: IAM Project ID fehlt IAMProjectIDMissing: IAM Project ID fehlt
IamProjectAlreadySet: IAM Project ID wurde bereits gesetzt IamProjectAlreadySet: IAM Project ID wurde bereits gesetzt
IdpInvalid: IDP Konfiguration ist ungültig IdpInvalid: IDP Konfiguration ist ungültig

View File

@ -271,8 +271,6 @@ Errors:
MemberAlreadyExisting: Member already exists MemberAlreadyExisting: Member already exists
MemberNotExisting: Member does not exist MemberNotExisting: Member does not exist
IDMissing: Id missing IDMissing: Id missing
GlobalOrgMissing: Global organization missing
GlobalOrgAlreadySet: Global organization has already been set
IAMProjectIDMissing: IAM project id missing IAMProjectIDMissing: IAM project id missing
IamProjectAlreadySet: IAM project id has already been set IamProjectAlreadySet: IAM project id has already been set
IdpInvalid: IDP configuration is invalid IdpInvalid: IDP configuration is invalid

View File

@ -269,8 +269,6 @@ Errors:
MemberAlreadyExisting: Il membro già esistente MemberAlreadyExisting: Il membro già esistente
MemberNotExisting: Il membro non esistente MemberNotExisting: Il membro non esistente
IDMissing: ID mancante IDMissing: ID mancante
GlobalOrgMissing: Manca un'organizzazione globale
GlobalOrgAlreadySet: L'organizzazione globale è già stata impostata
IAMProjectIDMissing: Manca l'ID del progetto IAM IAMProjectIDMissing: Manca l'ID del progetto IAM
IamProjectAlreadySet: L'ID del progetto IAM è già stato impostato IamProjectAlreadySet: L'ID del progetto IAM è già stato impostato
IdpInvalid: La configurazione dell'IDP non è valida IdpInvalid: La configurazione dell'IDP non è valida

View File

@ -423,6 +423,28 @@ service AdminService {
}; };
} }
// Set the default org
rpc SetDefaultOrg(SetDefaultOrgRequest) returns (SetDefaultOrgResponse) {
option (google.api.http) = {
put: "/orgs/default/{org_id}";
};
option (zitadel.v1.auth_option) = {
permission: "iam.write";
};
}
// Set the default org
rpc GetDefaultOrg(GetDefaultOrgRequest) returns (GetDefaultOrgResponse) {
option (google.api.http) = {
get: "/orgs/default";
};
option (zitadel.v1.auth_option) = {
permission: "iam.read";
};
}
//Returns all organisations matching the request //Returns all organisations matching the request
// all queries need to match (AND) // all queries need to match (AND)
rpc ListOrgs(ListOrgsRequest) returns (ListOrgsResponse) { rpc ListOrgs(ListOrgsRequest) returns (ListOrgsResponse) {
@ -2569,6 +2591,21 @@ message GetDefaultLanguageResponse {
string language = 1; string language = 1;
} }
message SetDefaultOrgRequest {
string org_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
}
message SetDefaultOrgResponse {
zitadel.v1.ObjectDetails details = 1;
}
//This is an empty request
message GetDefaultOrgRequest {}
message GetDefaultOrgResponse {
zitadel.org.v1.Org org = 1;
}
message ListInstanceDomainsRequest { message ListInstanceDomainsRequest {
zitadel.v1.ListQuery query = 1; zitadel.v1.ListQuery query = 1;
// the field the result is sorted // the field the result is sorted

View File

@ -2877,8 +2877,10 @@ message GetOIDCInformationResponse {
message GetIAMRequest {} message GetIAMRequest {}
message GetIAMResponse { message GetIAMResponse {
//deprecated: use default_org_id instead
string global_org_id = 1; string global_org_id = 1;
string iam_project_id = 2; string iam_project_id = 2;
string default_org_id = 3;
} }
//This is an empty request //This is an empty request