zitadel/internal/command/command.go

165 lines
5.6 KiB
Go
Raw Normal View History

package command
import (
"context"
"net/http"
"time"
"github.com/zitadel/zitadel/internal/api/authz"
api_http "github.com/zitadel/zitadel/internal/api/http"
"github.com/zitadel/zitadel/internal/command/preparation"
sd "github.com/zitadel/zitadel/internal/config/systemdefaults"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/id"
"github.com/zitadel/zitadel/internal/repository/action"
instance_repo "github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/keypair"
"github.com/zitadel/zitadel/internal/repository/org"
proj_repo "github.com/zitadel/zitadel/internal/repository/project"
"github.com/zitadel/zitadel/internal/repository/quota"
usr_repo "github.com/zitadel/zitadel/internal/repository/user"
usr_grant_repo "github.com/zitadel/zitadel/internal/repository/usergrant"
"github.com/zitadel/zitadel/internal/static"
webauthn_helper "github.com/zitadel/zitadel/internal/webauthn"
)
type Commands struct {
httpClient *http.Client
eventstore *eventstore.Eventstore
static static.Storage
idGenerator id.Generator
zitadelRoles []authz.RoleMapping
externalDomain string
externalSecure bool
externalPort uint16
idpConfigEncryption crypto.EncryptionAlgorithm
smtpEncryption crypto.EncryptionAlgorithm
smsEncryption crypto.EncryptionAlgorithm
userEncryption crypto.EncryptionAlgorithm
userPasswordAlg crypto.HashAlgorithm
machineKeySize int
applicationKeySize int
domainVerificationAlg crypto.EncryptionAlgorithm
domainVerificationGenerator crypto.Generator
domainVerificationValidator func(domain, token, verifier string, checkType api_http.CheckType) error
multifactors domain.MultifactorConfigs
webauthnConfig *webauthn_helper.Config
keySize int
keyAlgorithm crypto.EncryptionAlgorithm
certificateAlgorithm crypto.EncryptionAlgorithm
certKeySize int
privateKeyLifetime time.Duration
publicKeyLifetime time.Duration
certificateLifetime time.Duration
}
func StartCommands(es *eventstore.Eventstore,
defaults sd.SystemDefaults,
zitadelRoles []authz.RoleMapping,
staticStore static.Storage,
webAuthN *webauthn_helper.Config,
externalDomain string,
externalSecure bool,
externalPort uint16,
idpConfigEncryption,
otpEncryption,
smtpEncryption,
smsEncryption,
userEncryption,
domainVerificationEncryption,
oidcEncryption,
samlEncryption crypto.EncryptionAlgorithm,
httpClient *http.Client,
) (repo *Commands, err error) {
if externalDomain == "" {
return nil, errors.ThrowInvalidArgument(nil, "COMMAND-Df21s", "no external domain specified")
}
repo = &Commands{
eventstore: es,
static: staticStore,
feat: Configurable Unique Machine Identification (#3626) * feat: Configurable Unique Machine Identification This change fixes Segfault on AWS App Runner with v2 #3625 The change introduces two new dependencies: * github.com/drone/envsubst for supporting AWS ECS, which has its metadata endpoint described by an environment variable * github.com/jarcoal/jpath so that only relevant data from a metadata response is used to identify the machine. The change ads new configuration (see `defaults.yaml`): * `Machine.Identification` enables configuration of how machines are uniquely identified - I'm not sure about the top level category `Machine`, as I don't have anything else to add to it. Happy to hear suggestions for better naming or structure here. * `Machine.Identifiation.PrivateId` turns on or off the existing private IP based identification. Default is on. * `Machine.Identification.Hostname` turns on or off using the OS hostname to identify the machine. Great for most cloud environments, where this tends to be set to something that identifies the machine uniquely. Enabled by default. * `Machine.Identification.Webhook` configures identification based on the response to an HTTP GET request. Request headers can be configured, a JSONPath can be set for processing the response (no JSON parsing is done if this is not set), and the URL is allowed to contain environment variables in the format `"${var}"`. The new flow for getting a unique machine id is: 1. PrivateIP (if enabled) 2. Hostname (if enabled) 3. Webhook (if enabled, to configured URL) 4. Give up and error out. It's important that init configures machine identity first. Otherwise we could try to get an ID before configuring it. To prevent this from causing difficult to debug issues, where for example the default configuration was used, I've ensured that the application will generate an error if the module hasn't been configured and you try to get an ID. Misc changes: * Spelling and gramatical corrections to `init.go::New()` long description. * Spelling corrections to `verify_zitadel.go::newZitadel()`. * Updated `production.md` and `development.md` based on the new build process. I think the run instructions are also out of date, but I'll leave that for someone else. * `id.SonyFlakeGenerator` is now a function, which sets `id.sonyFlakeGenerator`, this allows us to defer initialization until configuration has been read. * Update internal/id/config.go Co-authored-by: Alexei-Barnes <82444470+Alexei-Barnes@users.noreply.github.com> * Fix authored by @livio-a for tests Co-authored-by: Livio Amstutz <livio.a@gmail.com>
2022-05-24 14:57:57 +00:00
idGenerator: id.SonyFlakeGenerator(),
zitadelRoles: zitadelRoles,
externalDomain: externalDomain,
externalSecure: externalSecure,
externalPort: externalPort,
keySize: defaults.KeyConfig.Size,
certKeySize: defaults.KeyConfig.CertificateSize,
privateKeyLifetime: defaults.KeyConfig.PrivateKeyLifetime,
publicKeyLifetime: defaults.KeyConfig.PublicKeyLifetime,
certificateLifetime: defaults.KeyConfig.CertificateLifetime,
idpConfigEncryption: idpConfigEncryption,
smtpEncryption: smtpEncryption,
smsEncryption: smsEncryption,
userEncryption: userEncryption,
domainVerificationAlg: domainVerificationEncryption,
keyAlgorithm: oidcEncryption,
certificateAlgorithm: samlEncryption,
webauthnConfig: webAuthN,
httpClient: httpClient,
}
feat(cli): setup (#3267) * commander * commander * selber! * move to packages * fix(errors): implement Is interface * test: command * test: commands * add init steps * setup tenant * add default step yaml * possibility to set password * merge v2 into v2-commander * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: rename iam command side to instance * fix: search query builder can filter events in memory * fix: filters for add member * fix(setup): add `ExternalSecure` to config * chore: name iam to instance * fix: matching * remove unsued func * base url * base url * test(command): filter funcs * test: commands * fix: rename orgiampolicy to domain policy * start from init * commands * config * fix indexes and add constraints * fixes * fix: merge conflicts * fix: protos * fix: md files * setup * add deprecated org iam policy again * typo * fix search query * fix filter * Apply suggestions from code review * remove custom org from org setup * add todos for verification * change apps creation * simplify package structure * fix error * move preparation helper for tests * fix unique constraints * fix config mapping in setup * fix error handling in encryption_keys.go * fix projection config * fix query from old views to projection * fix setup of mgmt api * set iam project and fix instance projection * imports Co-authored-by: Livio Amstutz <livio.a@gmail.com> Co-authored-by: fabi <fabienne.gerschwiler@gmail.com>
2022-03-28 08:05:09 +00:00
instance_repo.RegisterEventMappers(repo.eventstore)
org.RegisterEventMappers(repo.eventstore)
usr_repo.RegisterEventMappers(repo.eventstore)
usr_grant_repo.RegisterEventMappers(repo.eventstore)
proj_repo.RegisterEventMappers(repo.eventstore)
keypair.RegisterEventMappers(repo.eventstore)
action.RegisterEventMappers(repo.eventstore)
quota.RegisterEventMappers(repo.eventstore)
repo.userPasswordAlg = crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost)
repo.machineKeySize = int(defaults.SecretGenerators.MachineKeySize)
repo.applicationKeySize = int(defaults.SecretGenerators.ApplicationKeySize)
repo.multifactors = domain.MultifactorConfigs{
OTP: domain.OTPConfig{
CryptoMFA: otpEncryption,
Issuer: defaults.Multifactors.OTP.Issuer,
},
}
repo.domainVerificationGenerator = crypto.NewEncryptionGenerator(defaults.DomainVerification.VerificationGenerator, repo.domainVerificationAlg)
repo.domainVerificationValidator = api_http.ValidateDomain
return repo, nil
}
func AppendAndReduce(object interface {
AppendEvents(...eventstore.Event)
// TODO: Why is it allowed to return an error here?
Reduce() error
}, events ...eventstore.Event) error {
object.AppendEvents(events...)
return object.Reduce()
}
func queryAndReduce(ctx context.Context, filter preparation.FilterToQueryReducer, wm eventstore.QueryReducer) error {
events, err := filter(ctx, wm.Query())
if err != nil {
return err
}
if len(events) == 0 {
return nil
}
wm.AppendEvents(events...)
return wm.Reduce()
}
type existsWriteModel interface {
Exists() bool
eventstore.QueryReducer
}
func exists(ctx context.Context, filter preparation.FilterToQueryReducer, wm existsWriteModel) (bool, error) {
err := queryAndReduce(ctx, filter, wm)
if err != nil {
return false, err
}
return wm.Exists(), nil
}