diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0c78e99c67..8d30c91eec 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,10 +1,7 @@ blank_issues_enabled: true contact_links: - - name: 🚀 Feature Request - url: https://github.com/zitadel/zitadel/discussions/categories/ideas - about: Tell us about your idea in the discussions - name: ❓ Questions url: https://github.com/zitadel/zitadel/discussions/categories/q-a about: Ask for help in our Q&A discussions - - name: 💬 ZITADEL Chat + - name: 💬 ZITADEL Community Chat url: https://zitadel.com/chat diff --git a/.github/ISSUE_TEMPLATE/docs.yaml b/.github/ISSUE_TEMPLATE/docs.yaml index 777692f11a..04c1c0cdb1 100644 --- a/.github/ISSUE_TEMPLATE/docs.yaml +++ b/.github/ISSUE_TEMPLATE/docs.yaml @@ -1,6 +1,5 @@ name: 📄 Documentation description: Create an issue for missing or wrong documentation. -title: labels: ["docs"] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/improvement.yaml b/.github/ISSUE_TEMPLATE/improvement.yaml index 1cd8647552..2f68cb6170 100644 --- a/.github/ISSUE_TEMPLATE/improvement.yaml +++ b/.github/ISSUE_TEMPLATE/improvement.yaml @@ -1,6 +1,5 @@ name: 🛠️ Improvement -description: -title: +description: "Create an new issue for an improvment in ZITADEL" labels: ["improvement"] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/proposal.yaml b/.github/ISSUE_TEMPLATE/proposal.yaml index 29b08db5cb..5abded3eac 100644 --- a/.github/ISSUE_TEMPLATE/proposal.yaml +++ b/.github/ISSUE_TEMPLATE/proposal.yaml @@ -1,6 +1,5 @@ name: 💡 Proposal / Feature request -description: -title: +description: "Create an issue for a feature request/proposal." labels: ["enhancement"] body: - type: markdown diff --git a/SECURITY.md b/SECURITY.md index 76d07edb62..ae5179d96f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -47,7 +47,7 @@ We will not publish this information by default to protect your privacy. ## Disclosure Process -Our security team will follow the disclosure process: +Our security team will follow the disclosure process: 1. We will acknowledge the receipt of your vulnerability report 2. Our security team will try to verify, reproduce, and determine the impact of your report diff --git a/cmd/setup/03.go b/cmd/setup/03.go index 416010946a..ca1e0e21ca 100644 --- a/cmd/setup/03.go +++ b/cmd/setup/03.go @@ -23,10 +23,12 @@ type FirstInstance struct { DefaultLanguage language.Tag Org command.OrgSetup MachineKeyPath string + PatPath string instanceSetup command.InstanceSetup userEncryptionKey *crypto.KeyConfig smtpEncryptionKey *crypto.KeyConfig + oidcEncryptionKey *crypto.KeyConfig masterKey string db *sql.DB es *eventstore.Eventstore @@ -59,6 +61,14 @@ func (mig *FirstInstance) Execute(ctx context.Context) error { return err } + if err = verifyKey(mig.oidcEncryptionKey, keyStorage); err != nil { + return err + } + oidcEncryption, err := crypto.NewAESCrypto(mig.oidcEncryptionKey, keyStorage) + if err != nil { + return err + } + cmd, err := command.StartCommands(mig.es, mig.defaults, mig.zitadelRoles, @@ -73,13 +83,12 @@ func (mig *FirstInstance) Execute(ctx context.Context) error { nil, userAlg, nil, - nil, + oidcEncryption, nil, nil, nil, nil, ) - if err != nil { return err } @@ -101,25 +110,43 @@ func (mig *FirstInstance) Execute(ctx context.Context) error { } } - _, _, key, _, err := cmd.SetUpInstance(ctx, &mig.instanceSetup) - if key == nil { + _, token, key, _, err := cmd.SetUpInstance(ctx, &mig.instanceSetup) + if err != nil { + return err + } + if mig.instanceSetup.Org.Machine != nil && + ((mig.instanceSetup.Org.Machine.Pat != nil && token == "") || + (mig.instanceSetup.Org.Machine.MachineKey != nil && key == nil)) { return err } + if key != nil { + keyDetails, err := key.Detail() + if err != nil { + return err + } + if err := outputStdoutOrPath(mig.MachineKeyPath, string(keyDetails)); err != nil { + return err + } + } + if token != "" { + if err := outputStdoutOrPath(mig.PatPath, token); err != nil { + return err + } + } + return nil +} + +func outputStdoutOrPath(path string, content string) (err error) { f := os.Stdout - if mig.MachineKeyPath != "" { - f, err = os.OpenFile(mig.MachineKeyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if path != "" { + f, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return err } defer f.Close() } - - keyDetails, err := key.Detail() - if err != nil { - return err - } - _, err = fmt.Fprintln(f, string(keyDetails)) + _, err = fmt.Fprintln(f, content) return err } diff --git a/cmd/setup/config.go b/cmd/setup/config.go index 0d659e6e75..2f1bfbd6fa 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -72,6 +72,7 @@ type Steps struct { type encryptionKeyConfig struct { User *crypto.KeyConfig SMTP *crypto.KeyConfig + OIDC *crypto.KeyConfig } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 3f42503c2f..76f9637a2e 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -75,6 +75,7 @@ func Setup(config *Config, steps *Steps, masterKey string) { steps.FirstInstance.instanceSetup = config.DefaultInstance steps.FirstInstance.userEncryptionKey = config.EncryptionKeys.User steps.FirstInstance.smtpEncryptionKey = config.EncryptionKeys.SMTP + steps.FirstInstance.oidcEncryptionKey = config.EncryptionKeys.OIDC steps.FirstInstance.masterKey = masterKey steps.FirstInstance.db = dbClient.DB steps.FirstInstance.es = eventstoreClient diff --git a/cmd/setup/steps.yaml b/cmd/setup/steps.yaml index e495276e52..3164ac2f4c 100644 --- a/cmd/setup/steps.yaml +++ b/cmd/setup/steps.yaml @@ -1,5 +1,6 @@ FirstInstance: MachineKeyPath: + PatPath: InstanceName: ZITADEL DefaultLanguage: en Org: @@ -30,6 +31,8 @@ FirstInstance: MachineKey: ExpirationDate: Type: + Pat: + ExpirationDate: CorrectCreationDate: FailAfter: 5m diff --git a/internal/api/grpc/system/instance_converter.go b/internal/api/grpc/system/instance_converter.go index 304ab19c24..9aeea3e2c8 100644 --- a/internal/api/grpc/system/instance_converter.go +++ b/internal/api/grpc/system/instance_converter.go @@ -113,13 +113,11 @@ func createInstancePbToAddMachine(req *system_pb.CreateInstanceRequest_Machine, // Scopes are currently static and can not be overwritten Scopes: []string{oidc.ScopeOpenID, z_oidc.ScopeUserMetaData, z_oidc.ScopeResourceOwner}, } - - if !defaultMachine.Pat.ExpirationDate.IsZero() { - pat.ExpirationDate = defaultMachine.Pat.ExpirationDate - } else if req.PersonalAccessToken.ExpirationDate.IsValid() { + if req.GetPersonalAccessToken().GetExpirationDate().IsValid() { pat.ExpirationDate = req.PersonalAccessToken.ExpirationDate.AsTime() + } else if defaultMachine.Pat != nil && !defaultMachine.Pat.ExpirationDate.IsZero() { + pat.ExpirationDate = defaultMachine.Pat.ExpirationDate } - machine.Pat = &pat } diff --git a/internal/api/ui/login/external_provider_handler.go b/internal/api/ui/login/external_provider_handler.go index 2b7035c35e..abd07a70ec 100644 --- a/internal/api/ui/login/external_provider_handler.go +++ b/internal/api/ui/login/external_provider_handler.go @@ -292,14 +292,14 @@ func (l *Login) handleExternalUserAuthenticated( l.renderError(w, r, authReq, externalErr) return } - externalUser, externalUserChange, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, user, externalErr) + externalUser, externalUserChange, err := l.runPostExternalAuthenticationActions(externalUser, tokens(session), authReq, r, user, nil) if err != nil { l.renderError(w, r, authReq, err) return } // if action is done and no user linked then link or register if errors.IsNotFound(externalErr) { - l.externalUserNotExisting(w, r, authReq, provider, externalUser) + l.externalUserNotExisting(w, r, authReq, provider, externalUser, externalUserChange) return } if provider.IsAutoUpdate || len(externalUser.Metadatas) > 0 || externalUserChange { @@ -334,7 +334,7 @@ func (l *Login) handleExternalUserAuthenticated( // * external not found overview: // - creation by user // - linking to existing user -func (l *Login) externalUserNotExisting(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, provider *query.IDPTemplate, externalUser *domain.ExternalUser) { +func (l *Login) externalUserNotExisting(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, provider *query.IDPTemplate, externalUser *domain.ExternalUser, changed bool) { resourceOwner := authz.GetInstance(r.Context()).DefaultOrganisationID() if authReq.RequestedOrgID != "" && authReq.RequestedOrgID != resourceOwner { @@ -360,6 +360,12 @@ func (l *Login) externalUserNotExisting(w http.ResponseWriter, r *http.Request, l.renderExternalNotFoundOption(w, r, authReq, orgIAMPolicy, human, idpLink, err) return } + if changed { + if err := l.authRepo.SetLinkingUser(r.Context(), authReq, externalUser); err != nil { + l.renderError(w, r, authReq, err) + return + } + } l.autoCreateExternalUser(w, r, authReq) } diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go index 17f8893655..ffa70f9d60 100644 --- a/internal/auth/repository/auth_request.go +++ b/internal/auth/repository/auth_request.go @@ -17,6 +17,7 @@ type AuthRequestRepository interface { CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser, info *domain.BrowserInfo) error SetExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *domain.ExternalUser) error + SetLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error SelectUser(ctx context.Context, id, userID, userAgentID string) error SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error VerifyPassword(ctx context.Context, id, userID, resourceOwner, password, userAgentID string, info *domain.BrowserInfo) error diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index fcabd8f77f..6e7de351e6 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -278,6 +278,16 @@ func (repo *AuthRequestRepo) SetExternalUserLogin(ctx context.Context, authReqID return repo.AuthRequests.UpdateAuthRequest(ctx, request) } +func (repo *AuthRequestRepo) SetLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error { + for i, user := range request.LinkingUsers { + if user.ExternalUserID == externalUser.ExternalUserID { + request.LinkingUsers[i] = externalUser + return repo.AuthRequests.UpdateAuthRequest(ctx, request) + } + } + return nil +} + func (repo *AuthRequestRepo) setLinkingUser(ctx context.Context, request *domain.AuthRequest, externalUser *domain.ExternalUser) error { request.LinkingUsers = append(request.LinkingUsers, externalUser) return repo.AuthRequests.UpdateAuthRequest(ctx, request) diff --git a/internal/query/projection/idp_template.go b/internal/query/projection/idp_template.go index 80fee7e479..14a50c6a1a 100644 --- a/internal/query/projection/idp_template.go +++ b/internal/query/projection/idp_template.go @@ -351,6 +351,10 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer { Event: instance.OIDCIDPMigratedAzureADEventType, Reduce: p.reduceOIDCIDPMigratedAzureAD, }, + { + Event: instance.OIDCIDPMigratedGoogleEventType, + Reduce: p.reduceOIDCIDPMigratedGoogle, + }, { Event: instance.JWTIDPAddedEventType, Reduce: p.reduceJWTIDPAdded, @@ -472,6 +476,14 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer { Event: org.OIDCIDPChangedEventType, Reduce: p.reduceOIDCIDPChanged, }, + { + Event: org.OIDCIDPMigratedAzureADEventType, + Reduce: p.reduceOIDCIDPMigratedAzureAD, + }, + { + Event: org.OIDCIDPMigratedGoogleEventType, + Reduce: p.reduceOIDCIDPMigratedGoogle, + }, { Event: org.JWTIDPAddedEventType, Reduce: p.reduceJWTIDPAdded, diff --git a/internal/repository/instance/idp.go b/internal/repository/instance/idp.go index b2d42d8eeb..7e41c35a1a 100644 --- a/internal/repository/instance/idp.go +++ b/internal/repository/instance/idp.go @@ -263,7 +263,7 @@ func NewOIDCIDPMigratedGoogleEvent( eventstore.NewBaseEventForPush( ctx, aggregate, - OIDCIDPMigratedAzureADEventType, + OIDCIDPMigratedGoogleEventType, ), id, name,