mirror of
https://github.com/zitadel/zitadel.git
synced 2025-07-28 09:13:42 +00:00
feat(crypto): use passwap for machine and app secrets (#7657)
* feat(crypto): use passwap for machine and app secrets * fix command package tests * add hash generator command test * naming convention, fix query tests * rename PasswordHasher and cleanup start commands * add reducer tests * fix intergration tests, cleanup old config * add app secret unit tests * solve setup panics * fix push of updated events * add missing event translations * update documentation * solve linter errors * remove nolint:SA1019 as it doesn't seem to help anyway * add nolint to deprecated filter usage * update users migration version * remove unused ClientSecret from APIConfigChangedEvent --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
parent
5931fb8f28
commit
2089992d75
4
Makefile
4
Makefile
@ -115,6 +115,10 @@ core_integration_setup:
|
|||||||
core_integration_test: core_integration_setup
|
core_integration_test: core_integration_setup
|
||||||
go test -tags=integration -race -p 1 -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./...
|
go test -tags=integration -race -p 1 -coverprofile=profile.cov -coverpkg=./internal/...,./cmd/... ./...
|
||||||
|
|
||||||
|
.PHONY: core_integration_test_fast
|
||||||
|
core_integration_test_fast: core_integration_setup
|
||||||
|
go test -tags=integration -p 1 ./...
|
||||||
|
|
||||||
.PHONY: console_lint
|
.PHONY: console_lint
|
||||||
console_lint:
|
console_lint:
|
||||||
cd console && \
|
cd console && \
|
||||||
|
@ -428,7 +428,6 @@ SystemAPIUsers:
|
|||||||
|
|
||||||
SystemDefaults:
|
SystemDefaults:
|
||||||
SecretGenerators:
|
SecretGenerators:
|
||||||
PasswordSaltCost: 14 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_PASSWORDSALTCOST
|
|
||||||
MachineKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_MACHINEKEYSIZE
|
MachineKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_MACHINEKEYSIZE
|
||||||
ApplicationKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_APPLICATIONKEYSIZE
|
ApplicationKeySize: 2048 # ZITADEL_SYSTEMDEFAULTS_SECRETGENERATORS_APPLICATIONKEYSIZE
|
||||||
PasswordHasher:
|
PasswordHasher:
|
||||||
@ -482,6 +481,13 @@ SystemDefaults:
|
|||||||
# - "md5"
|
# - "md5"
|
||||||
# - "scrypt"
|
# - "scrypt"
|
||||||
# - "pbkdf2" # verifier for all pbkdf2 hash modes.
|
# - "pbkdf2" # verifier for all pbkdf2 hash modes.
|
||||||
|
SecretHasher:
|
||||||
|
# Set hasher configuration for machine users, API and OIDC client secrets.
|
||||||
|
# See PasswordHasher for all possible options
|
||||||
|
Hasher:
|
||||||
|
Algorithm: "bcrypt" # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_ALGORITHM
|
||||||
|
Cost: 4 # ZITADEL_SYSTEMDEFAULTS_SECRETHASHER_HASHER_COST
|
||||||
|
Verifiers:
|
||||||
Multifactors:
|
Multifactors:
|
||||||
OTP:
|
OTP:
|
||||||
# If this is empty, the issuer is the requested domain
|
# If this is empty, the issuer is the requested domain
|
||||||
@ -590,7 +596,6 @@ DefaultInstance:
|
|||||||
# date format: 2023-01-01T00:00:00Z
|
# date format: 2023-01-01T00:00:00Z
|
||||||
ExpirationDate: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE
|
ExpirationDate: # ZITADEL_DEFAULTINSTANCE_ORG_MACHINE_PAT_EXPIRATIONDATE
|
||||||
SecretGenerators:
|
SecretGenerators:
|
||||||
PasswordSaltCost: 14 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_PASSWORDSALTCOST
|
|
||||||
ClientSecret:
|
ClientSecret:
|
||||||
Length: 64 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_LENGTH
|
Length: 64 # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_LENGTH
|
||||||
IncludeLowerLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDELOWERLETTERS
|
IncludeLowerLetters: true # ZITADEL_DEFAULTINSTANCE_SECRETGENERATORS_CLIENTSECRET_INCLUDELOWERLETTERS
|
||||||
|
@ -23,5 +23,5 @@ func (mig *User11AddLowerFieldsToVerifiedEmail) Execute(ctx context.Context, _ e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mig *User11AddLowerFieldsToVerifiedEmail) String() string {
|
func (mig *User11AddLowerFieldsToVerifiedEmail) String() string {
|
||||||
return "25_user11_add_lower_fields_to_verified_email"
|
return "25_user12_add_lower_fields_to_verified_email"
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
ALTER TABLE IF EXISTS projections.users11_notifications ADD COLUMN IF NOT EXISTS verified_email_lower TEXT GENERATED ALWAYS AS (lower(verified_email)) STORED;
|
ALTER TABLE IF EXISTS projections.users12_notifications ADD COLUMN IF NOT EXISTS verified_email_lower TEXT GENERATED ALWAYS AS (lower(verified_email)) STORED;
|
||||||
CREATE INDEX IF NOT EXISTS users11_notifications_email_search ON projections.users11_notifications (instance_id, verified_email_lower);
|
CREATE INDEX IF NOT EXISTS users12_notifications_email_search ON projections.users12_notifications (instance_id, verified_email_lower);
|
||||||
|
@ -439,7 +439,7 @@ func startAPIs(
|
|||||||
}
|
}
|
||||||
apis.RegisterHandlerOnPrefix(openapi.HandlerPrefix, openAPIHandler)
|
apis.RegisterHandlerOnPrefix(openapi.HandlerPrefix, openAPIHandler)
|
||||||
|
|
||||||
oidcServer, err := oidc.NewServer(config.OIDC, login.DefaultLoggedOutPath, config.ExternalSecure, commands, queries, authRepo, keys.OIDC, keys.OIDCKey, eventstore, dbClient, userAgentInterceptor, instanceInterceptor.Handler, limitingAccessInterceptor, config.Log.Slog())
|
oidcServer, err := oidc.NewServer(ctx, config.OIDC, login.DefaultLoggedOutPath, config.ExternalSecure, commands, queries, authRepo, keys.OIDC, keys.OIDCKey, eventstore, dbClient, userAgentInterceptor, instanceInterceptor.Handler, limitingAccessInterceptor, config.Log.Slog(), config.SystemDefaults.SecretHasher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to start oidc provider: %w", err)
|
return nil, fmt.Errorf("unable to start oidc provider: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ ZITADEL hashes all Passwords and Client Secrets in an non reversible way to furt
|
|||||||
Passwords and secrets are always hashed with a random salt and stored as an encoded string that contains the Algorithm, its Parameters, Salt and Hash.
|
Passwords and secrets are always hashed with a random salt and stored as an encoded string that contains the Algorithm, its Parameters, Salt and Hash.
|
||||||
The storage encoding used by ZITADEL is Modular Crypt Format and a full reference can be found in our [Passwap library](https://github.com/zitadel/passwap#encoding).
|
The storage encoding used by ZITADEL is Modular Crypt Format and a full reference can be found in our [Passwap library](https://github.com/zitadel/passwap#encoding).
|
||||||
|
|
||||||
The following hash algorithms are supported for user passwords:
|
The following hash algorithms are supported:
|
||||||
|
|
||||||
- argon2i / id[^1]
|
- argon2i / id[^1]
|
||||||
- bcrypt (Default)
|
- bcrypt (Default)
|
||||||
@ -82,8 +82,6 @@ This allows to increase cost along with growing computing power.
|
|||||||
ZITADEL allows to import user passwords from systems that use any of the above hashing algorithms.
|
ZITADEL allows to import user passwords from systems that use any of the above hashing algorithms.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Client Secrets always use bcrypt.
|
|
||||||
|
|
||||||
### Encrypted Secrets
|
### Encrypted Secrets
|
||||||
|
|
||||||
Some secrets cannot be hashed because they need to be used in their raw form. These include:
|
Some secrets cannot be hashed because they need to be used in their raw form. These include:
|
||||||
|
@ -292,7 +292,7 @@ func getFileFromGCS(ctx context.Context, input *admin_pb.ImportDataRequest_GCSIn
|
|||||||
return ioutil.ReadAll(reader)
|
return ioutil.ReadAll(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
func importOrg1(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, ctxData authz.CtxData, org *admin_pb.DataOrg, success *admin_pb.ImportDataSuccess, count *counts, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode, appSecretGenerator crypto.Generator) error {
|
func importOrg1(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, ctxData authz.CtxData, org *admin_pb.DataOrg, success *admin_pb.ImportDataSuccess, count *counts, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode crypto.Generator) error {
|
||||||
_, err := s.command.AddOrgWithID(ctx, org.GetOrg().GetName(), ctxData.UserID, ctxData.ResourceOwner, org.GetOrgId(), []string{})
|
_, err := s.command.AddOrgWithID(ctx, org.GetOrg().GetName(), ctxData.UserID, ctxData.ResourceOwner, org.GetOrgId(), []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "org", Id: org.GetOrgId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "org", Id: org.GetOrgId(), Message: err.Error()})
|
||||||
@ -325,7 +325,7 @@ func importOrg1(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataEr
|
|||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "domain_policy", Id: org.GetOrgId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "domain_policy", Id: org.GetOrgId(), Message: err.Error()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return importResources(ctx, s, errors, successOrg, org, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode, appSecretGenerator)
|
return importResources(ctx, s, errors, successOrg, org, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func importLabelPolicy(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, org *admin_pb.DataOrg) error {
|
func importLabelPolicy(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, org *admin_pb.DataOrg) error {
|
||||||
@ -584,13 +584,13 @@ func importProjects(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importOIDCApps(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts, appSecretGenerator crypto.Generator) error {
|
func importOIDCApps(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) error {
|
||||||
if org.OidcApps == nil {
|
if org.OidcApps == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, app := range org.GetOidcApps() {
|
for _, app := range org.GetOidcApps() {
|
||||||
logging.Debugf("import oidcapplication: %s", app.GetAppId())
|
logging.Debugf("import oidcapplication: %s", app.GetAppId())
|
||||||
_, err := s.command.AddOIDCApplicationWithID(ctx, management.AddOIDCAppRequestToDomain(app.App), org.GetOrgId(), app.GetAppId(), appSecretGenerator)
|
_, err := s.command.AddOIDCApplicationWithID(ctx, management.AddOIDCAppRequestToDomain(app.App), org.GetOrgId(), app.GetAppId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "oidc_app", Id: app.GetAppId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "oidc_app", Id: app.GetAppId(), Message: err.Error()})
|
||||||
if isCtxTimeout(ctx) {
|
if isCtxTimeout(ctx) {
|
||||||
@ -605,13 +605,13 @@ func importOIDCApps(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importAPIApps(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts, appSecretGenerator crypto.Generator) error {
|
func importAPIApps(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts) error {
|
||||||
if org.ApiApps == nil {
|
if org.ApiApps == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for _, app := range org.GetApiApps() {
|
for _, app := range org.GetApiApps() {
|
||||||
logging.Debugf("import apiapplication: %s", app.GetAppId())
|
logging.Debugf("import apiapplication: %s", app.GetAppId())
|
||||||
_, err := s.command.AddAPIApplicationWithID(ctx, management.AddAPIAppRequestToDomain(app.GetApp()), org.GetOrgId(), app.GetAppId(), appSecretGenerator)
|
_, err := s.command.AddAPIApplicationWithID(ctx, management.AddAPIAppRequestToDomain(app.GetApp()), org.GetOrgId(), app.GetAppId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
*errors = append(*errors, &admin_pb.ImportDataError{Type: "api_app", Id: app.GetAppId(), Message: err.Error()})
|
*errors = append(*errors, &admin_pb.ImportDataError{Type: "api_app", Id: app.GetAppId(), Message: err.Error()})
|
||||||
if isCtxTimeout(ctx) {
|
if isCtxTimeout(ctx) {
|
||||||
@ -700,7 +700,7 @@ func importProjectRoles(ctx context.Context, s *Server, errors *[]*admin_pb.Impo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func importResources(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode, appSecretGenerator crypto.Generator) error {
|
func importResources(ctx context.Context, s *Server, errors *[]*admin_pb.ImportDataError, successOrg *admin_pb.ImportDataSuccessOrg, org *admin_pb.DataOrg, count *counts, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode crypto.Generator) error {
|
||||||
if err := importOrgDomains(ctx, s, errors, successOrg, org); err != nil {
|
if err := importOrgDomains(ctx, s, errors, successOrg, org); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -742,10 +742,10 @@ func importResources(ctx context.Context, s *Server, errors *[]*admin_pb.ImportD
|
|||||||
if err := importProjects(ctx, s, errors, successOrg, org, count); err != nil {
|
if err := importProjects(ctx, s, errors, successOrg, org, count); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := importOIDCApps(ctx, s, errors, successOrg, org, count, appSecretGenerator); err != nil {
|
if err := importOIDCApps(ctx, s, errors, successOrg, org, count); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := importAPIApps(ctx, s, errors, successOrg, org, count, appSecretGenerator); err != nil {
|
if err := importAPIApps(ctx, s, errors, successOrg, org, count); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := importAppKeys(ctx, s, errors, successOrg, org, count); err != nil {
|
if err := importAppKeys(ctx, s, errors, successOrg, org, count); err != nil {
|
||||||
@ -1023,10 +1023,6 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
|
|||||||
success := &admin_pb.ImportDataSuccess{}
|
success := &admin_pb.ImportDataSuccess{}
|
||||||
count := &counts{}
|
count := &counts{}
|
||||||
|
|
||||||
appSecretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
initCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeInitCode, s.userCodeAlg)
|
initCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeInitCode, s.userCodeAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -1064,7 +1060,7 @@ func (s *Server) importData(ctx context.Context, orgs []*admin_pb.DataOrg) (*adm
|
|||||||
count.appKeysCount += len(org.GetAppKeys())
|
count.appKeysCount += len(org.GetAppKeys())
|
||||||
}
|
}
|
||||||
for _, org := range orgs {
|
for _, org := range orgs {
|
||||||
if err = importOrg1(ctx, s, &errors, ctxData, org, success, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode, appSecretGenerator); err != nil {
|
if err = importOrg1(ctx, s, &errors, ctxData, org, success, count, initCodeGenerator, emailCodeGenerator, phoneCodeGenerator, passwordlessInitCode); err != nil {
|
||||||
return &admin_pb.ImportDataResponse{Errors: errors, Success: success}, count, err
|
return &admin_pb.ImportDataResponse{Errors: errors, Success: success}, count, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ type Server struct {
|
|||||||
query *query.Queries
|
query *query.Queries
|
||||||
assetsAPIDomain func(context.Context) string
|
assetsAPIDomain func(context.Context) string
|
||||||
userCodeAlg crypto.EncryptionAlgorithm
|
userCodeAlg crypto.EncryptionAlgorithm
|
||||||
passwordHashAlg crypto.HashAlgorithm
|
|
||||||
auditLogRetention time.Duration
|
auditLogRetention time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +52,6 @@ func CreateServer(
|
|||||||
query: query,
|
query: query,
|
||||||
assetsAPIDomain: assets.AssetAPI(externalSecure),
|
assetsAPIDomain: assets.AssetAPI(externalSecure),
|
||||||
userCodeAlg: userCodeAlg,
|
userCodeAlg: userCodeAlg,
|
||||||
passwordHashAlg: crypto.NewBCrypt(sd.SecretGenerators.PasswordSaltCost),
|
|
||||||
auditLogRetention: auditLogRetention,
|
auditLogRetention: auditLogRetention,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
change_grpc "github.com/zitadel/zitadel/internal/api/grpc/change"
|
change_grpc "github.com/zitadel/zitadel/internal/api/grpc/change"
|
||||||
object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
project_grpc "github.com/zitadel/zitadel/internal/api/grpc/project"
|
project_grpc "github.com/zitadel/zitadel/internal/api/grpc/project"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/repository/project"
|
"github.com/zitadel/zitadel/internal/repository/project"
|
||||||
@ -81,11 +80,7 @@ func (s *Server) ListAppChanges(ctx context.Context, req *mgmt_pb.ListAppChanges
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddOIDCApp(ctx context.Context, req *mgmt_pb.AddOIDCAppRequest) (*mgmt_pb.AddOIDCAppResponse, error) {
|
func (s *Server) AddOIDCApp(ctx context.Context, req *mgmt_pb.AddOIDCAppRequest) (*mgmt_pb.AddOIDCAppResponse, error) {
|
||||||
appSecretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
app, err := s.command.AddOIDCApplication(ctx, AddOIDCAppRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
app, err := s.command.AddOIDCApplication(ctx, AddOIDCAppRequestToDomain(req), authz.GetCtxData(ctx).OrgID, appSecretGenerator)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -110,11 +105,7 @@ func (s *Server) AddSAMLApp(ctx context.Context, req *mgmt_pb.AddSAMLAppRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddAPIApp(ctx context.Context, req *mgmt_pb.AddAPIAppRequest) (*mgmt_pb.AddAPIAppResponse, error) {
|
func (s *Server) AddAPIApp(ctx context.Context, req *mgmt_pb.AddAPIAppRequest) (*mgmt_pb.AddAPIAppResponse, error) {
|
||||||
appSecretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
app, err := s.command.AddAPIApplication(ctx, AddAPIAppRequestToDomain(req), authz.GetCtxData(ctx).OrgID)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
app, err := s.command.AddAPIApplication(ctx, AddAPIAppRequestToDomain(req), authz.GetCtxData(ctx).OrgID, appSecretGenerator)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -209,11 +200,7 @@ func (s *Server) RemoveApp(ctx context.Context, req *mgmt_pb.RemoveAppRequest) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, req *mgmt_pb.RegenerateOIDCClientSecretRequest) (*mgmt_pb.RegenerateOIDCClientSecretResponse, error) {
|
func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, req *mgmt_pb.RegenerateOIDCClientSecretRequest) (*mgmt_pb.RegenerateOIDCClientSecretResponse, error) {
|
||||||
appSecretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
config, err := s.command.ChangeOIDCApplicationSecret(ctx, req.ProjectId, req.AppId, authz.GetCtxData(ctx).OrgID)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config, err := s.command.ChangeOIDCApplicationSecret(ctx, req.ProjectId, req.AppId, authz.GetCtxData(ctx).OrgID, appSecretGenerator)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -228,11 +215,7 @@ func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, req *mgmt_pb.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RegenerateAPIClientSecret(ctx context.Context, req *mgmt_pb.RegenerateAPIClientSecretRequest) (*mgmt_pb.RegenerateAPIClientSecretResponse, error) {
|
func (s *Server) RegenerateAPIClientSecret(ctx context.Context, req *mgmt_pb.RegenerateAPIClientSecretRequest) (*mgmt_pb.RegenerateAPIClientSecretResponse, error) {
|
||||||
appSecretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
config, err := s.command.ChangeAPIApplicationSecret(ctx, req.ProjectId, req.AppId, authz.GetCtxData(ctx).OrgID)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
config, err := s.command.ChangeAPIApplicationSecret(ctx, req.ProjectId, req.AppId, authz.GetCtxData(ctx).OrgID, appSecretGenerator)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ type Server struct {
|
|||||||
query *query.Queries
|
query *query.Queries
|
||||||
systemDefaults systemdefaults.SystemDefaults
|
systemDefaults systemdefaults.SystemDefaults
|
||||||
assetAPIPrefix func(context.Context) string
|
assetAPIPrefix func(context.Context) string
|
||||||
passwordHashAlg crypto.HashAlgorithm
|
|
||||||
userCodeAlg crypto.EncryptionAlgorithm
|
userCodeAlg crypto.EncryptionAlgorithm
|
||||||
externalSecure bool
|
externalSecure bool
|
||||||
}
|
}
|
||||||
@ -44,7 +43,6 @@ func CreateServer(
|
|||||||
query: query,
|
query: query,
|
||||||
systemDefaults: sd,
|
systemDefaults: sd,
|
||||||
assetAPIPrefix: assets.AssetAPI(externalSecure),
|
assetAPIPrefix: assets.AssetAPI(externalSecure),
|
||||||
passwordHashAlg: crypto.NewBCrypt(sd.SecretGenerators.PasswordSaltCost),
|
|
||||||
userCodeAlg: userCodeAlg,
|
userCodeAlg: userCodeAlg,
|
||||||
externalSecure: externalSecure,
|
externalSecure: externalSecure,
|
||||||
}
|
}
|
||||||
|
@ -800,18 +800,13 @@ func (s *Server) RemoveMachineKey(ctx context.Context, req *mgmt_pb.RemoveMachin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) GenerateMachineSecret(ctx context.Context, req *mgmt_pb.GenerateMachineSecretRequest) (*mgmt_pb.GenerateMachineSecretResponse, error) {
|
func (s *Server) GenerateMachineSecret(ctx context.Context, req *mgmt_pb.GenerateMachineSecretRequest) (*mgmt_pb.GenerateMachineSecretResponse, error) {
|
||||||
// use SecretGeneratorTypeAppSecret as the secrets will be used in the client_credentials grant like a client secret
|
|
||||||
secretGenerator, err := s.query.InitHashGenerator(ctx, domain.SecretGeneratorTypeAppSecret, s.passwordHashAlg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
user, err := s.getUserByID(ctx, req.GetUserId())
|
user, err := s.getUserByID(ctx, req.GetUserId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
set := new(command.GenerateMachineSecret)
|
set := new(command.GenerateMachineSecret)
|
||||||
details, err := s.command.GenerateMachineSecret(ctx, req.UserId, authz.GetCtxData(ctx).OrgID, secretGenerator, set)
|
details, err := s.command.GenerateMachineSecret(ctx, req.UserId, authz.GetCtxData(ctx).OrgID, set)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func MachineToPb(view *query.Machine) *user_pb.Machine {
|
|||||||
return &user_pb.Machine{
|
return &user_pb.Machine{
|
||||||
Name: view.Name,
|
Name: view.Name,
|
||||||
Description: view.Description,
|
Description: view.Description,
|
||||||
HasSecret: view.Secret != nil,
|
HasSecret: view.EncodedSecret != "",
|
||||||
AccessTokenType: AccessTokenTypeToPb(view.AccessTokenType),
|
AccessTokenType: AccessTokenTypeToPb(view.AccessTokenType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ func machineToPb(userQ *query.Machine) *user.MachineUser {
|
|||||||
return &user.MachineUser{
|
return &user.MachineUser{
|
||||||
Name: userQ.Name,
|
Name: userQ.Name,
|
||||||
Description: userQ.Description,
|
Description: userQ.Description,
|
||||||
HasSecret: userQ.Secret != nil,
|
HasSecret: userQ.EncodedSecret != "",
|
||||||
AccessTokenType: accessTokenTypeToPb(userQ.AccessTokenType),
|
AccessTokenType: accessTokenTypeToPb(userQ.AccessTokenType),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1050,8 +1050,13 @@ func (s *Server) verifyClientSecret(ctx context.Context, client *query.OIDCClien
|
|||||||
if secret == "" {
|
if secret == "" {
|
||||||
return oidc.ErrInvalidClient().WithDescription("empty client secret")
|
return oidc.ErrInvalidClient().WithDescription("empty client secret")
|
||||||
}
|
}
|
||||||
if err = crypto.CompareHash(client.ClientSecret, []byte(secret), s.hashAlg); err != nil {
|
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
|
||||||
|
updated, err := s.hasher.Verify(client.HashedSecret, secret)
|
||||||
|
spanPasswordComparison.EndWithError(err)
|
||||||
|
if err != nil {
|
||||||
|
s.command.OIDCSecretCheckFailed(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner)
|
||||||
return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid secret")
|
return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid secret")
|
||||||
}
|
}
|
||||||
|
s.command.OIDCSecretCheckSucceeded(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner, updated)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ import (
|
|||||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||||
"github.com/zitadel/oidc/v3/pkg/op"
|
"github.com/zitadel/oidc/v3/pkg/op"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,15 +41,18 @@ func (s *Server) clientCredentialsAuth(ctx context.Context, clientID, clientSecr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err // defaults to server error
|
return nil, err // defaults to server error
|
||||||
}
|
}
|
||||||
if user.Machine == nil || user.Machine.Secret == nil {
|
if user.Machine == nil || user.Machine.EncodedSecret == "" {
|
||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-pieP8", "Errors.User.Machine.Secret.NotExisting")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-pieP8", "Errors.User.Machine.Secret.NotExisting")
|
||||||
}
|
}
|
||||||
if err = crypto.CompareHash(user.Machine.Secret, []byte(clientSecret), s.hashAlg); err != nil {
|
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
|
||||||
|
updated, err := s.hasher.Verify(user.Machine.EncodedSecret, clientSecret)
|
||||||
|
spanPasswordComparison.EndWithError(err)
|
||||||
|
if err != nil {
|
||||||
s.command.MachineSecretCheckFailed(ctx, user.ID, user.ResourceOwner)
|
s.command.MachineSecretCheckFailed(ctx, user.ID, user.ResourceOwner)
|
||||||
return nil, zerrors.ThrowInvalidArgument(err, "OIDC-VoXo6", "Errors.User.Machine.Secret.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(err, "OIDC-VoXo6", "Errors.User.Machine.Secret.Invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.command.MachineSecretCheckSucceeded(ctx, user.ID, user.ResourceOwner)
|
s.command.MachineSecretCheckSucceeded(ctx, user.ID, user.ResourceOwner, updated)
|
||||||
return &clientCredentialsClient{
|
return &clientCredentialsClient{
|
||||||
id: clientID,
|
id: clientID,
|
||||||
user: user,
|
user: user,
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/zitadel/oidc/v3/pkg/op"
|
"github.com/zitadel/oidc/v3/pkg/op"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
@ -149,8 +148,8 @@ func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCrede
|
|||||||
return client.ClientID, client.ProjectID, nil
|
return client.ClientID, client.ProjectID, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
if client.ClientSecret != nil {
|
if client.HashedSecret != "" {
|
||||||
if err := crypto.CompareHash(client.ClientSecret, []byte(cc.ClientSecret), s.hashAlg); err != nil {
|
if err := s.introspectionClientSecretAuth(ctx, client, cc.ClientSecret); err != nil {
|
||||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||||
}
|
}
|
||||||
return client.ClientID, client.ProjectID, nil
|
return client.ClientID, client.ProjectID, nil
|
||||||
@ -167,6 +166,35 @@ func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCrede
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errNoAppType = errors.New("introspection client without app type")
|
||||||
|
|
||||||
|
func (s *Server) introspectionClientSecretAuth(ctx context.Context, client *query.IntrospectionClient, secret string) error {
|
||||||
|
var (
|
||||||
|
successCommand func(ctx context.Context, appID, projectID, resourceOwner, updated string)
|
||||||
|
failedCommand func(ctx context.Context, appID, projectID, resourceOwner string)
|
||||||
|
)
|
||||||
|
switch client.AppType {
|
||||||
|
case query.AppTypeAPI:
|
||||||
|
successCommand = s.command.APISecretCheckSucceeded
|
||||||
|
failedCommand = s.command.APISecretCheckFailed
|
||||||
|
case query.AppTypeOIDC:
|
||||||
|
successCommand = s.command.OIDCSecretCheckSucceeded
|
||||||
|
failedCommand = s.command.OIDCSecretCheckFailed
|
||||||
|
default:
|
||||||
|
return zerrors.ThrowInternal(errNoAppType, "OIDC-ooD5Ot", "Errors.Internal")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
|
||||||
|
updated, err := s.hasher.Verify(client.HashedSecret, secret)
|
||||||
|
spanPasswordComparison.EndWithError(err)
|
||||||
|
if err != nil {
|
||||||
|
failedCommand(ctx, client.AppID, client.ProjectID, client.ResourceOwner)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
successCommand(ctx, client.AppID, client.ProjectID, client.ResourceOwner, updated)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// clientFromCredentials parses the client ID early,
|
// clientFromCredentials parses the client ID early,
|
||||||
// and makes a single query for the client for either auth methods.
|
// and makes a single query for the client for either auth methods.
|
||||||
func (s *Server) clientFromCredentials(ctx context.Context, cc *op.ClientCredentials) (client *query.IntrospectionClient, err error) {
|
func (s *Server) clientFromCredentials(ctx context.Context, cc *op.ClientCredentials) (client *query.IntrospectionClient, err error) {
|
||||||
|
@ -80,6 +80,7 @@ type OPStorage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(
|
func NewServer(
|
||||||
|
ctx context.Context,
|
||||||
config Config,
|
config Config,
|
||||||
defaultLogoutRedirectURI string,
|
defaultLogoutRedirectURI string,
|
||||||
externalSecure bool,
|
externalSecure bool,
|
||||||
@ -93,13 +94,14 @@ func NewServer(
|
|||||||
userAgentCookie, instanceHandler func(http.Handler) http.Handler,
|
userAgentCookie, instanceHandler func(http.Handler) http.Handler,
|
||||||
accessHandler *middleware.AccessInterceptor,
|
accessHandler *middleware.AccessInterceptor,
|
||||||
fallbackLogger *slog.Logger,
|
fallbackLogger *slog.Logger,
|
||||||
|
hashConfig crypto.HashConfig,
|
||||||
) (*Server, error) {
|
) (*Server, error) {
|
||||||
opConfig, err := createOPConfig(config, defaultLogoutRedirectURI, cryptoKey)
|
opConfig, err := createOPConfig(config, defaultLogoutRedirectURI, cryptoKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
|
return nil, zerrors.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
|
||||||
}
|
}
|
||||||
storage := newStorage(config, command, query, repo, encryptionAlg, es, projections, externalSecure)
|
storage := newStorage(config, command, query, repo, encryptionAlg, es, projections, externalSecure)
|
||||||
keyCache := newPublicKeyCache(context.TODO(), config.PublicKeyCacheMaxAge, query.GetPublicKeyByID)
|
keyCache := newPublicKeyCache(ctx, config.PublicKeyCacheMaxAge, query.GetPublicKeyByID)
|
||||||
accessTokenKeySet := newOidcKeySet(keyCache, withKeyExpiryCheck(true))
|
accessTokenKeySet := newOidcKeySet(keyCache, withKeyExpiryCheck(true))
|
||||||
idTokenHintKeySet := newOidcKeySet(keyCache)
|
idTokenHintKeySet := newOidcKeySet(keyCache)
|
||||||
|
|
||||||
@ -119,7 +121,10 @@ func NewServer(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInternal(err, "OIDC-DAtg3", "cannot create provider")
|
return nil, zerrors.ThrowInternal(err, "OIDC-DAtg3", "cannot create provider")
|
||||||
}
|
}
|
||||||
|
hasher, err := hashConfig.NewHasher()
|
||||||
|
if err != nil {
|
||||||
|
return nil, zerrors.ThrowInternal(err, "OIDC-Aij4e", "cannot create secret hasher")
|
||||||
|
}
|
||||||
server := &Server{
|
server := &Server{
|
||||||
LegacyServer: op.NewLegacyServer(provider, endpoints(config.CustomEndpoints)),
|
LegacyServer: op.NewLegacyServer(provider, endpoints(config.CustomEndpoints)),
|
||||||
repo: repo,
|
repo: repo,
|
||||||
@ -133,7 +138,7 @@ func NewServer(
|
|||||||
defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime,
|
defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime,
|
||||||
defaultIdTokenLifetime: config.DefaultIdTokenLifetime,
|
defaultIdTokenLifetime: config.DefaultIdTokenLifetime,
|
||||||
fallbackLogger: fallbackLogger,
|
fallbackLogger: fallbackLogger,
|
||||||
hashAlg: crypto.NewBCrypt(10), // as we are only verifying in oidc, the cost is already part of the hash string and the config here is irrelevant.
|
hasher: hasher,
|
||||||
signingKeyAlgorithm: config.SigningKeyAlgorithm,
|
signingKeyAlgorithm: config.SigningKeyAlgorithm,
|
||||||
assetAPIPrefix: assets.AssetAPI(externalSecure),
|
assetAPIPrefix: assets.AssetAPI(externalSecure),
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ type Server struct {
|
|||||||
defaultIdTokenLifetime time.Duration
|
defaultIdTokenLifetime time.Duration
|
||||||
|
|
||||||
fallbackLogger *slog.Logger
|
fallbackLogger *slog.Logger
|
||||||
hashAlg crypto.HashAlgorithm
|
hasher *crypto.Hasher
|
||||||
signingKeyAlgorithm string
|
signingKeyAlgorithm string
|
||||||
assetAPIPrefix func(ctx context.Context) string
|
assetAPIPrefix func(ctx context.Context) string
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -34,8 +35,9 @@ type Commands struct {
|
|||||||
jobs sync.WaitGroup
|
jobs sync.WaitGroup
|
||||||
|
|
||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
newCode cryptoCodeFunc
|
newEncryptedCode encrypedCodeFunc
|
||||||
newCodeWithDefault cryptoCodeWithDefaultFunc
|
newEncryptedCodeWithDefault encryptedCodeWithDefaultFunc
|
||||||
|
newHashedSecret hashedSecretFunc
|
||||||
|
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
static static.Storage
|
static static.Storage
|
||||||
@ -49,8 +51,8 @@ type Commands struct {
|
|||||||
smtpEncryption crypto.EncryptionAlgorithm
|
smtpEncryption crypto.EncryptionAlgorithm
|
||||||
smsEncryption crypto.EncryptionAlgorithm
|
smsEncryption crypto.EncryptionAlgorithm
|
||||||
userEncryption crypto.EncryptionAlgorithm
|
userEncryption crypto.EncryptionAlgorithm
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
codeAlg crypto.HashAlgorithm
|
secretHasher *crypto.Hasher
|
||||||
machineKeySize int
|
machineKeySize int
|
||||||
applicationKeySize int
|
applicationKeySize int
|
||||||
domainVerificationAlg crypto.EncryptionAlgorithm
|
domainVerificationAlg crypto.EncryptionAlgorithm
|
||||||
@ -106,6 +108,15 @@ func StartCommands(
|
|||||||
idGenerator := id.SonyFlakeGenerator()
|
idGenerator := id.SonyFlakeGenerator()
|
||||||
// reuse the oidcEncryption to be able to handle both tokens in the interceptor later on
|
// reuse the oidcEncryption to be able to handle both tokens in the interceptor later on
|
||||||
sessionAlg := oidcEncryption
|
sessionAlg := oidcEncryption
|
||||||
|
|
||||||
|
secretHasher, err := defaults.SecretHasher.NewHasher()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("secret hasher: %w", err)
|
||||||
|
}
|
||||||
|
userPasswordHasher, err := defaults.PasswordHasher.NewHasher()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("password hasher: %w", err)
|
||||||
|
}
|
||||||
repo = &Commands{
|
repo = &Commands{
|
||||||
eventstore: es,
|
eventstore: es,
|
||||||
static: staticStore,
|
static: staticStore,
|
||||||
@ -123,14 +134,20 @@ func StartCommands(
|
|||||||
smtpEncryption: smtpEncryption,
|
smtpEncryption: smtpEncryption,
|
||||||
smsEncryption: smsEncryption,
|
smsEncryption: smsEncryption,
|
||||||
userEncryption: userEncryption,
|
userEncryption: userEncryption,
|
||||||
|
userPasswordHasher: userPasswordHasher,
|
||||||
|
secretHasher: secretHasher,
|
||||||
|
machineKeySize: int(defaults.SecretGenerators.MachineKeySize),
|
||||||
|
applicationKeySize: int(defaults.SecretGenerators.ApplicationKeySize),
|
||||||
domainVerificationAlg: domainVerificationEncryption,
|
domainVerificationAlg: domainVerificationEncryption,
|
||||||
|
domainVerificationGenerator: crypto.NewEncryptionGenerator(defaults.DomainVerification.VerificationGenerator, domainVerificationEncryption),
|
||||||
|
domainVerificationValidator: api_http.ValidateDomain,
|
||||||
keyAlgorithm: oidcEncryption,
|
keyAlgorithm: oidcEncryption,
|
||||||
certificateAlgorithm: samlEncryption,
|
certificateAlgorithm: samlEncryption,
|
||||||
webauthnConfig: webAuthN,
|
webauthnConfig: webAuthN,
|
||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
checkPermission: permissionCheck,
|
checkPermission: permissionCheck,
|
||||||
newCode: newCryptoCode,
|
newEncryptedCode: newEncryptedCode,
|
||||||
newCodeWithDefault: newCryptoCodeWithDefaultConfig,
|
newEncryptedCodeWithDefault: newEncryptedCodeWithDefaultConfig,
|
||||||
sessionTokenCreator: sessionTokenCreator(idGenerator, sessionAlg),
|
sessionTokenCreator: sessionTokenCreator(idGenerator, sessionAlg),
|
||||||
sessionTokenVerifier: sessionTokenVerifier,
|
sessionTokenVerifier: sessionTokenVerifier,
|
||||||
defaultAccessTokenLifetime: defaultAccessTokenLifetime,
|
defaultAccessTokenLifetime: defaultAccessTokenLifetime,
|
||||||
@ -145,25 +162,17 @@ func StartCommands(
|
|||||||
GrpcServiceExisting: func(service string) bool { return false },
|
GrpcServiceExisting: func(service string) bool { return false },
|
||||||
GrpcMethodExisting: func(method string) bool { return false },
|
GrpcMethodExisting: func(method string) bool { return false },
|
||||||
ActionFunctionExisting: domain.FunctionExists(),
|
ActionFunctionExisting: domain.FunctionExists(),
|
||||||
}
|
multifactors: domain.MultifactorConfigs{
|
||||||
|
|
||||||
repo.codeAlg = crypto.NewBCrypt(defaults.SecretGenerators.PasswordSaltCost)
|
|
||||||
repo.userPasswordHasher, err = defaults.PasswordHasher.PasswordHasher()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
repo.machineKeySize = int(defaults.SecretGenerators.MachineKeySize)
|
|
||||||
repo.applicationKeySize = int(defaults.SecretGenerators.ApplicationKeySize)
|
|
||||||
|
|
||||||
repo.multifactors = domain.MultifactorConfigs{
|
|
||||||
OTP: domain.OTPConfig{
|
OTP: domain.OTPConfig{
|
||||||
CryptoMFA: otpEncryption,
|
CryptoMFA: otpEncryption,
|
||||||
Issuer: defaults.Multifactors.OTP.Issuer,
|
Issuer: defaults.Multifactors.OTP.Issuer,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.domainVerificationGenerator = crypto.NewEncryptionGenerator(defaults.DomainVerification.VerificationGenerator, repo.domainVerificationAlg)
|
if defaultSecretGenerators != nil && defaultSecretGenerators.ClientSecret != nil {
|
||||||
repo.domainVerificationValidator = api_http.ValidateDomain
|
repo.newHashedSecret = newHashedSecretWithDefault(secretHasher, defaultSecretGenerators.ClientSecret)
|
||||||
|
}
|
||||||
return repo, nil
|
return repo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,27 +7,26 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type cryptoCodeFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error)
|
type encrypedCodeFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error)
|
||||||
|
|
||||||
type cryptoCodeWithDefaultFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto, defaultConfig *crypto.GeneratorConfig) (*CryptoCode, error)
|
type encryptedCodeWithDefaultFunc func(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (*EncryptedCode, error)
|
||||||
|
|
||||||
var emptyConfig = &crypto.GeneratorConfig{}
|
var emptyConfig = &crypto.GeneratorConfig{}
|
||||||
|
|
||||||
type CryptoCode struct {
|
type EncryptedCode struct {
|
||||||
Crypted *crypto.CryptoValue
|
Crypted *crypto.CryptoValue
|
||||||
Plain string
|
Plain string
|
||||||
Expiry time.Duration
|
Expiry time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error) {
|
func newEncryptedCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return newCryptoCodeWithDefaultConfig(ctx, filter, typ, alg, emptyConfig)
|
return newEncryptedCodeWithDefaultConfig(ctx, filter, typ, alg, emptyConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoCodeWithDefaultConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto, defaultConfig *crypto.GeneratorConfig) (*CryptoCode, error) {
|
func newEncryptedCodeWithDefaultConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (*EncryptedCode, error) {
|
||||||
gen, config, err := secretGenerator(ctx, filter, typ, alg, defaultConfig)
|
gen, config, err := encryptedCodeGenerator(ctx, filter, typ, alg, defaultConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -35,41 +34,47 @@ func newCryptoCodeWithDefaultConfig(ctx context.Context, filter preparation.Filt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &CryptoCode{
|
return &EncryptedCode{
|
||||||
Crypted: crypted,
|
Crypted: crypted,
|
||||||
Plain: plain,
|
Plain: plain,
|
||||||
Expiry: config.Expiry,
|
Expiry: config.Expiry,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyCryptoCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto, creation time.Time, expiry time.Duration, crypted *crypto.CryptoValue, plain string) error {
|
func verifyEncryptedCode(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, creation time.Time, expiry time.Duration, crypted *crypto.CryptoValue, plain string) error {
|
||||||
gen, _, err := secretGenerator(ctx, filter, typ, alg, emptyConfig)
|
gen, _, err := encryptedCodeGenerator(ctx, filter, typ, alg, emptyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return crypto.VerifyCode(creation, expiry, crypted, plain, gen)
|
return crypto.VerifyCode(creation, expiry, crypted, plain, gen.Alg())
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretGenerator(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.Crypto, defaultConfig *crypto.GeneratorConfig) (crypto.Generator, *crypto.GeneratorConfig, error) {
|
func encryptedCodeGenerator(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, defaultConfig *crypto.GeneratorConfig) (crypto.Generator, *crypto.GeneratorConfig, error) {
|
||||||
config, err := secretGeneratorConfigWithDefault(ctx, filter, typ, defaultConfig)
|
config, err := cryptoGeneratorConfigWithDefault(ctx, filter, typ, defaultConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
switch a := alg.(type) {
|
return crypto.NewEncryptionGenerator(*config, alg), config, nil
|
||||||
case crypto.HashAlgorithm:
|
}
|
||||||
return crypto.NewHashGenerator(*config, a), config, nil
|
|
||||||
case crypto.EncryptionAlgorithm:
|
type hashedSecretFunc func(ctx context.Context, filter preparation.FilterToQueryReducer) (encodedHash, plain string, err error)
|
||||||
return crypto.NewEncryptionGenerator(*config, a), config, nil
|
|
||||||
default:
|
func newHashedSecretWithDefault(hasher *crypto.Hasher, defaultConfig *crypto.GeneratorConfig) hashedSecretFunc {
|
||||||
return nil, nil, zerrors.ThrowInternalf(nil, "COMMA-RreV6", "Errors.Internal unsupported crypto algorithm type %T", a)
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) (encodedHash string, plain string, err error) {
|
||||||
|
config, err := cryptoGeneratorConfigWithDefault(ctx, filter, domain.SecretGeneratorTypeAppSecret, defaultConfig)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
generator := crypto.NewHashGenerator(*config, hasher)
|
||||||
|
return generator.NewCode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretGeneratorConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType) (*crypto.GeneratorConfig, error) {
|
func cryptoGeneratorConfig(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType) (*crypto.GeneratorConfig, error) {
|
||||||
return secretGeneratorConfigWithDefault(ctx, filter, typ, emptyConfig)
|
return cryptoGeneratorConfigWithDefault(ctx, filter, typ, emptyConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func secretGeneratorConfigWithDefault(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, defaultConfig *crypto.GeneratorConfig) (*crypto.GeneratorConfig, error) {
|
func cryptoGeneratorConfigWithDefault(ctx context.Context, filter preparation.FilterToQueryReducer, typ domain.SecretGeneratorType, defaultConfig *crypto.GeneratorConfig) (*crypto.GeneratorConfig, error) {
|
||||||
wm := NewInstanceSecretGeneratorConfigWriteModel(ctx, typ)
|
wm := NewInstanceSecretGeneratorConfigWriteModel(ctx, typ)
|
||||||
events, err := filter(ctx, wm.Query())
|
events, err := filter(ctx, wm.Query())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zitadel/passwap"
|
||||||
|
"github.com/zitadel/passwap/bcrypt"
|
||||||
"go.uber.org/mock/gomock"
|
"go.uber.org/mock/gomock"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
@ -15,12 +17,11 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func mockCode(code string, exp time.Duration) cryptoCodeFunc {
|
func mockEncryptedCode(code string, exp time.Duration) encrypedCodeFunc {
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.Crypto) (*CryptoCode, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return &CryptoCode{
|
return &EncryptedCode{
|
||||||
Crypted: &crypto.CryptoValue{
|
Crypted: &crypto.CryptoValue{
|
||||||
CryptoType: crypto.TypeEncryption,
|
CryptoType: crypto.TypeEncryption,
|
||||||
Algorithm: "enc",
|
Algorithm: "enc",
|
||||||
@ -33,9 +34,9 @@ func mockCode(code string, exp time.Duration) cryptoCodeFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockCodeWithDefault(code string, exp time.Duration) cryptoCodeWithDefaultFunc {
|
func mockEncryptedCodeWithDefault(code string, exp time.Duration) encryptedCodeWithDefaultFunc {
|
||||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.Crypto, _ *crypto.GeneratorConfig) (*CryptoCode, error) {
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer, _ domain.SecretGeneratorType, alg crypto.EncryptionAlgorithm, _ *crypto.GeneratorConfig) (*EncryptedCode, error) {
|
||||||
return &CryptoCode{
|
return &EncryptedCode{
|
||||||
Crypted: &crypto.CryptoValue{
|
Crypted: &crypto.CryptoValue{
|
||||||
CryptoType: crypto.TypeEncryption,
|
CryptoType: crypto.TypeEncryption,
|
||||||
Algorithm: "enc",
|
Algorithm: "enc",
|
||||||
@ -48,6 +49,12 @@ func mockCodeWithDefault(code string, exp time.Duration) cryptoCodeWithDefaultFu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mockHashedSecret(secret string) hashedSecretFunc {
|
||||||
|
return func(_ context.Context, _ preparation.FilterToQueryReducer) (encodedHash string, plain string, err error) {
|
||||||
|
return secret, secret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testGeneratorConfig = crypto.GeneratorConfig{
|
testGeneratorConfig = crypto.GeneratorConfig{
|
||||||
Length: 12,
|
Length: 12,
|
||||||
@ -74,7 +81,7 @@ func testSecretGeneratorAddedEvent(typ domain.SecretGeneratorType) *instance.Sec
|
|||||||
func Test_newCryptoCode(t *testing.T) {
|
func Test_newCryptoCode(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
typ domain.SecretGeneratorType
|
typ domain.SecretGeneratorType
|
||||||
alg crypto.Crypto
|
alg crypto.EncryptionAlgorithm
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -87,7 +94,7 @@ func Test_newCryptoCode(t *testing.T) {
|
|||||||
eventstore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
eventstore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
},
|
},
|
||||||
wantErr: io.ErrClosedPipe,
|
wantErr: io.ErrClosedPipe,
|
||||||
},
|
},
|
||||||
@ -98,13 +105,13 @@ func Test_newCryptoCode(t *testing.T) {
|
|||||||
)),
|
)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := newCryptoCode(context.Background(), tt.eventstore.Filter, tt.args.typ, tt.args.alg)
|
got, err := newEncryptedCode(context.Background(), tt.eventstore.Filter, tt.args.typ, tt.args.alg) //nolint:staticcheck
|
||||||
require.ErrorIs(t, err, tt.wantErr)
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
if tt.wantErr == nil {
|
if tt.wantErr == nil {
|
||||||
require.NotNil(t, got)
|
require.NotNil(t, got)
|
||||||
@ -120,12 +127,12 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
es := eventstoreExpect(t, expectFilter(
|
es := eventstoreExpect(t, expectFilter(
|
||||||
eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypeVerifyEmailCode)),
|
eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypeVerifyEmailCode)),
|
||||||
))
|
))
|
||||||
code, err := newCryptoCode(context.Background(), es.Filter, domain.SecretGeneratorTypeVerifyEmailCode, crypto.CreateMockHashAlg(gomock.NewController(t)))
|
code, err := newEncryptedCode(context.Background(), es.Filter, domain.SecretGeneratorTypeVerifyEmailCode, crypto.CreateMockEncryptionAlg(gomock.NewController(t))) //nolint:staticcheck
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
typ domain.SecretGeneratorType
|
typ domain.SecretGeneratorType
|
||||||
alg crypto.Crypto
|
alg crypto.EncryptionAlgorithm
|
||||||
expiry time.Duration
|
expiry time.Duration
|
||||||
crypted *crypto.CryptoValue
|
crypted *crypto.CryptoValue
|
||||||
plain string
|
plain string
|
||||||
@ -141,7 +148,7 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
eventsore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
eventsore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
expiry: code.Expiry,
|
expiry: code.Expiry,
|
||||||
crypted: code.Crypted,
|
crypted: code.Crypted,
|
||||||
plain: code.Plain,
|
plain: code.Plain,
|
||||||
@ -155,7 +162,7 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
)),
|
)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
expiry: code.Expiry,
|
expiry: code.Expiry,
|
||||||
crypted: code.Crypted,
|
crypted: code.Crypted,
|
||||||
plain: code.Plain,
|
plain: code.Plain,
|
||||||
@ -168,7 +175,7 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
)),
|
)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
expiry: code.Expiry,
|
expiry: code.Expiry,
|
||||||
crypted: code.Crypted,
|
crypted: code.Crypted,
|
||||||
plain: "wrong",
|
plain: "wrong",
|
||||||
@ -178,7 +185,7 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
err := verifyCryptoCode(context.Background(), tt.eventsore.Filter, tt.args.typ, tt.args.alg, time.Now(), tt.args.expiry, tt.args.crypted, tt.args.plain)
|
err := verifyEncryptedCode(context.Background(), tt.eventsore.Filter, tt.args.typ, tt.args.alg, time.Now(), tt.args.expiry, tt.args.crypted, tt.args.plain) //nolint:staticcheck
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
return
|
return
|
||||||
@ -188,10 +195,10 @@ func Test_verifyCryptoCode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_secretGenerator(t *testing.T) {
|
func Test_cryptoCodeGenerator(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
typ domain.SecretGeneratorType
|
typ domain.SecretGeneratorType
|
||||||
alg crypto.Crypto
|
alg crypto.EncryptionAlgorithm
|
||||||
defaultConfig *crypto.GeneratorConfig
|
defaultConfig *crypto.GeneratorConfig
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -207,24 +214,11 @@ func Test_secretGenerator(t *testing.T) {
|
|||||||
eventsore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
eventsore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
||||||
args: args{
|
args: args{
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
defaultConfig: emptyConfig,
|
defaultConfig: emptyConfig,
|
||||||
},
|
},
|
||||||
wantErr: io.ErrClosedPipe,
|
wantErr: io.ErrClosedPipe,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "hash generator",
|
|
||||||
eventsore: eventstoreExpect(t, expectFilter(
|
|
||||||
eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypeVerifyEmailCode)),
|
|
||||||
)),
|
|
||||||
args: args{
|
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
defaultConfig: emptyConfig,
|
|
||||||
},
|
|
||||||
want: crypto.NewHashGenerator(testGeneratorConfig, crypto.CreateMockHashAlg(gomock.NewController(t))),
|
|
||||||
wantConf: &testGeneratorConfig,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "encryption generator",
|
name: "encryption generator",
|
||||||
eventsore: eventstoreExpect(t, expectFilter(
|
eventsore: eventstoreExpect(t, expectFilter(
|
||||||
@ -238,17 +232,6 @@ func Test_secretGenerator(t *testing.T) {
|
|||||||
want: crypto.NewEncryptionGenerator(testGeneratorConfig, crypto.CreateMockEncryptionAlg(gomock.NewController(t))),
|
want: crypto.NewEncryptionGenerator(testGeneratorConfig, crypto.CreateMockEncryptionAlg(gomock.NewController(t))),
|
||||||
wantConf: &testGeneratorConfig,
|
wantConf: &testGeneratorConfig,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "hash generator with default config",
|
|
||||||
eventsore: eventstoreExpect(t, expectFilter()),
|
|
||||||
args: args{
|
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
|
||||||
alg: crypto.CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
defaultConfig: &testGeneratorConfig,
|
|
||||||
},
|
|
||||||
want: crypto.NewHashGenerator(testGeneratorConfig, crypto.CreateMockHashAlg(gomock.NewController(t))),
|
|
||||||
wantConf: &testGeneratorConfig,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "encryption generator with default config",
|
name: "encryption generator with default config",
|
||||||
eventsore: eventstoreExpect(t, expectFilter()),
|
eventsore: eventstoreExpect(t, expectFilter()),
|
||||||
@ -260,25 +243,79 @@ func Test_secretGenerator(t *testing.T) {
|
|||||||
want: crypto.NewEncryptionGenerator(testGeneratorConfig, crypto.CreateMockEncryptionAlg(gomock.NewController(t))),
|
want: crypto.NewEncryptionGenerator(testGeneratorConfig, crypto.CreateMockEncryptionAlg(gomock.NewController(t))),
|
||||||
wantConf: &testGeneratorConfig,
|
wantConf: &testGeneratorConfig,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "unsupported type",
|
|
||||||
eventsore: eventstoreExpect(t, expectFilter(
|
|
||||||
eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypeVerifyEmailCode)),
|
|
||||||
)),
|
|
||||||
args: args{
|
|
||||||
typ: domain.SecretGeneratorTypeVerifyEmailCode,
|
|
||||||
alg: nil,
|
|
||||||
defaultConfig: emptyConfig,
|
|
||||||
},
|
|
||||||
wantErr: zerrors.ThrowInternalf(nil, "COMMA-RreV6", "Errors.Internal unsupported crypto algorithm type %T", nil),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, gotConf, err := secretGenerator(context.Background(), tt.eventsore.Filter, tt.args.typ, tt.args.alg, tt.args.defaultConfig)
|
got, gotConf, err := encryptedCodeGenerator(context.Background(), tt.eventsore.Filter, tt.args.typ, tt.args.alg, tt.args.defaultConfig) //nolint:staticcheck
|
||||||
require.ErrorIs(t, err, tt.wantErr)
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
assert.IsType(t, tt.want, got)
|
assert.IsType(t, tt.want, got)
|
||||||
assert.Equal(t, tt.wantConf, gotConf)
|
assert.Equal(t, tt.wantConf, gotConf)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_newHashedSecretWithDefault(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
|
wantLen int
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "filter error",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilterError(io.ErrClosedPipe),
|
||||||
|
),
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "default config",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(),
|
||||||
|
),
|
||||||
|
wantLen: 32,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "instance config",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
instance.NewSecretGeneratorAddedEvent(context.Background(),
|
||||||
|
&instance.NewAggregate("INSTANCE").Aggregate,
|
||||||
|
domain.SecretGeneratorTypeAppSecret,
|
||||||
|
24,
|
||||||
|
time.Hour*1,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantLen: 24,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
hasher := &crypto.Hasher{
|
||||||
|
Swapper: passwap.NewSwapper(bcrypt.New(bcrypt.MinCost)),
|
||||||
|
}
|
||||||
|
defaultConfig := &crypto.GeneratorConfig{
|
||||||
|
Length: 32,
|
||||||
|
Expiry: time.Minute,
|
||||||
|
IncludeLowerLetters: true,
|
||||||
|
}
|
||||||
|
generate := newHashedSecretWithDefault(hasher, defaultConfig)
|
||||||
|
encodedHash, plain, err := generate(context.Background(), tt.eventstore(t).Filter) //nolint:staticcheck
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, plain, tt.wantLen)
|
||||||
|
_, err = hasher.Verify(encodedHash, plain)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,6 +23,6 @@ func (e *Email) Validate() error {
|
|||||||
return e.Address.Validate()
|
return e.Address.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) newEmailCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) {
|
func (c *Commands) newEmailCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return c.newCode(ctx, filter, domain.SecretGeneratorTypeVerifyEmailCode, alg)
|
return c.newEncryptedCode(ctx, filter, domain.SecretGeneratorTypeVerifyEmailCode, alg)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ func (wm *OAuthIDPWriteModel) NewChanges(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
@ -278,7 +278,7 @@ func (wm *OIDCIDPWriteModel) NewChanges(
|
|||||||
issuer,
|
issuer,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
idTokenMapping bool,
|
idTokenMapping bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
@ -636,7 +636,7 @@ func (wm *AzureADIDPWriteModel) NewChanges(
|
|||||||
name string,
|
name string,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
tenant string,
|
tenant string,
|
||||||
isEmailVerified bool,
|
isEmailVerified bool,
|
||||||
@ -772,7 +772,7 @@ func (wm *GitHubIDPWriteModel) NewChanges(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.GitHubIDPChanges, error) {
|
) ([]idp.GitHubIDPChanges, error) {
|
||||||
@ -904,7 +904,7 @@ func (wm *GitHubEnterpriseIDPWriteModel) NewChanges(
|
|||||||
name,
|
name,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint string,
|
||||||
@ -1037,7 +1037,7 @@ func (wm *GitLabIDPWriteModel) NewChanges(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.GitLabIDPChanges, error) {
|
) ([]idp.GitLabIDPChanges, error) {
|
||||||
@ -1161,7 +1161,7 @@ func (wm *GitLabSelfHostedIDPWriteModel) NewChanges(
|
|||||||
issuer string,
|
issuer string,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.GitLabSelfHostedIDPChanges, error) {
|
) ([]idp.GitLabSelfHostedIDPChanges, error) {
|
||||||
@ -1285,7 +1285,7 @@ func (wm *GoogleIDPWriteModel) NewChanges(
|
|||||||
name string,
|
name string,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.GoogleIDPChanges, error) {
|
) ([]idp.GoogleIDPChanges, error) {
|
||||||
@ -1460,7 +1460,7 @@ func (wm *LDAPIDPWriteModel) NewChanges(
|
|||||||
userObjectClasses []string,
|
userObjectClasses []string,
|
||||||
userFilters []string,
|
userFilters []string,
|
||||||
timeout time.Duration,
|
timeout time.Duration,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
attributes idp.LDAPAttributes,
|
attributes idp.LDAPAttributes,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.LDAPIDPChanges, error) {
|
) ([]idp.LDAPIDPChanges, error) {
|
||||||
@ -1653,7 +1653,7 @@ func (wm *AppleIDPWriteModel) NewChanges(
|
|||||||
teamID string,
|
teamID string,
|
||||||
keyID string,
|
keyID string,
|
||||||
privateKey []byte,
|
privateKey []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) ([]idp.AppleIDPChanges, error) {
|
) ([]idp.AppleIDPChanges, error) {
|
||||||
@ -1790,7 +1790,7 @@ func (wm *SAMLIDPWriteModel) NewChanges(
|
|||||||
metadata,
|
metadata,
|
||||||
key,
|
key,
|
||||||
certificate []byte,
|
certificate []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
binding string,
|
binding string,
|
||||||
withSignedRequest bool,
|
withSignedRequest bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
|
@ -126,7 +126,6 @@ type SetQuotas struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SecretGenerators struct {
|
type SecretGenerators struct {
|
||||||
PasswordSaltCost uint
|
|
||||||
ClientSecret *crypto.GeneratorConfig
|
ClientSecret *crypto.GeneratorConfig
|
||||||
InitializeUserCode *crypto.GeneratorConfig
|
InitializeUserCode *crypto.GeneratorConfig
|
||||||
EmailVerificationCode *crypto.GeneratorConfig
|
EmailVerificationCode *crypto.GeneratorConfig
|
||||||
@ -457,7 +456,6 @@ func setupMinimalInterfaces(commands *Commands, validations *[]preparation.Valid
|
|||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
},
|
},
|
||||||
nil,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
commands.AddAPIAppCommand(
|
commands.AddAPIAppCommand(
|
||||||
@ -469,7 +467,6 @@ func setupMinimalInterfaces(commands *Commands, validations *[]preparation.Valid
|
|||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
},
|
},
|
||||||
nil,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
commands.AddAPIAppCommand(
|
commands.AddAPIAppCommand(
|
||||||
@ -481,10 +478,9 @@ func setupMinimalInterfaces(commands *Commands, validations *[]preparation.Valid
|
|||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
},
|
},
|
||||||
nil,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
commands.AddOIDCAppCommand(cnsl, nil),
|
commands.AddOIDCAppCommand(cnsl),
|
||||||
SetIAMConsoleID(instanceAgg, &cnsl.ClientID, &ids.consoleAppID),
|
SetIAMConsoleID(instanceAgg, &cnsl.ClientID, &ids.consoleAppID),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
@ -141,12 +140,7 @@ func TestCommandSide_AddInstanceDomain(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"consoleApplicationID",
|
"consoleApplicationID",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
@ -61,7 +61,7 @@ func (wm *InstanceOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
@ -171,7 +171,7 @@ func (wm *InstanceOIDCIDPWriteModel) NewChangedEvent(
|
|||||||
issuer,
|
issuer,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
idTokenMapping bool,
|
idTokenMapping bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
@ -344,7 +344,7 @@ func (wm *InstanceAzureADIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
tenant string,
|
tenant string,
|
||||||
isEmailVerified bool,
|
isEmailVerified bool,
|
||||||
@ -420,7 +420,7 @@ func (wm *InstanceGitHubIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.GitHubIDPChangedEvent, error) {
|
) (*instance.GitHubIDPChangedEvent, error) {
|
||||||
@ -485,7 +485,7 @@ func (wm *InstanceGitHubEnterpriseIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint string,
|
||||||
@ -563,7 +563,7 @@ func (wm *InstanceGitLabIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.GitLabIDPChangedEvent, error) {
|
) (*instance.GitLabIDPChangedEvent, error) {
|
||||||
@ -629,7 +629,7 @@ func (wm *InstanceGitLabSelfHostedIDPWriteModel) NewChangedEvent(
|
|||||||
issuer,
|
issuer,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.GitLabSelfHostedIDPChangedEvent, error) {
|
) (*instance.GitLabSelfHostedIDPChangedEvent, error) {
|
||||||
@ -695,7 +695,7 @@ func (wm *InstanceGoogleIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.GoogleIDPChangedEvent, error) {
|
) (*instance.GoogleIDPChangedEvent, error) {
|
||||||
@ -767,7 +767,7 @@ func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
|||||||
userObjectClasses []string,
|
userObjectClasses []string,
|
||||||
userFilters []string,
|
userFilters []string,
|
||||||
timeout time.Duration,
|
timeout time.Duration,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
attributes idp.LDAPAttributes,
|
attributes idp.LDAPAttributes,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.LDAPIDPChangedEvent, error) {
|
) (*instance.LDAPIDPChangedEvent, error) {
|
||||||
@ -848,7 +848,7 @@ func (wm *InstanceAppleIDPWriteModel) NewChangedEvent(
|
|||||||
teamID,
|
teamID,
|
||||||
keyID string,
|
keyID string,
|
||||||
privateKey []byte,
|
privateKey []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*instance.AppleIDPChangedEvent, error) {
|
) (*instance.AppleIDPChangedEvent, error) {
|
||||||
@ -912,7 +912,7 @@ func (wm *InstanceSAMLIDPWriteModel) NewChangedEvent(
|
|||||||
metadata,
|
metadata,
|
||||||
key,
|
key,
|
||||||
certificate []byte,
|
certificate []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
binding string,
|
binding string,
|
||||||
withSignedRequest bool,
|
withSignedRequest bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
|
@ -93,7 +93,7 @@ func (wm *InstanceIDPOIDCConfigWriteModel) NewChangedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
idpDisplayNameMapping,
|
idpDisplayNameMapping,
|
||||||
userNameMapping domain.OIDCMappingField,
|
userNameMapping domain.OIDCMappingField,
|
||||||
scopes ...string,
|
scopes ...string,
|
||||||
|
@ -279,8 +279,8 @@ func (h plainHasher) Verify(encoded, password string) (verifier.Result, error) {
|
|||||||
//
|
//
|
||||||
// With `x` set to "foo", the following encoded string would be produced by Hash:
|
// With `x` set to "foo", the following encoded string would be produced by Hash:
|
||||||
// $plain$foo$password
|
// $plain$foo$password
|
||||||
func mockPasswordHasher(x string) *crypto.PasswordHasher {
|
func mockPasswordHasher(x string) *crypto.Hasher {
|
||||||
return &crypto.PasswordHasher{
|
return &crypto.Hasher{
|
||||||
Swapper: passwap.NewSwapper(plainHasher{x: x}),
|
Swapper: passwap.NewSwapper(plainHasher{x: x}),
|
||||||
Prefixes: []string{"$plain$"},
|
Prefixes: []string{"$plain$"},
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ func (wm *OrgOAuthIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint,
|
userEndpoint,
|
||||||
@ -173,7 +173,7 @@ func (wm *OrgOIDCIDPWriteModel) NewChangedEvent(
|
|||||||
issuer,
|
issuer,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
idTokenMapping bool,
|
idTokenMapping bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
@ -350,7 +350,7 @@ func (wm *OrgAzureADIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
tenant string,
|
tenant string,
|
||||||
isEmailVerified bool,
|
isEmailVerified bool,
|
||||||
@ -426,7 +426,7 @@ func (wm *OrgGitHubIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.GitHubIDPChangedEvent, error) {
|
) (*org.GitHubIDPChangedEvent, error) {
|
||||||
@ -492,7 +492,7 @@ func (wm *OrgGitHubEnterpriseIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
userEndpoint string,
|
userEndpoint string,
|
||||||
@ -571,7 +571,7 @@ func (wm *OrgGitLabIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.GitLabIDPChangedEvent, error) {
|
) (*org.GitLabIDPChangedEvent, error) {
|
||||||
@ -637,7 +637,7 @@ func (wm *OrgGitLabSelfHostedIDPWriteModel) NewChangedEvent(
|
|||||||
issuer,
|
issuer,
|
||||||
clientID string,
|
clientID string,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.GitLabSelfHostedIDPChangedEvent, error) {
|
) (*org.GitLabSelfHostedIDPChangedEvent, error) {
|
||||||
@ -705,7 +705,7 @@ func (wm *OrgGoogleIDPWriteModel) NewChangedEvent(
|
|||||||
name,
|
name,
|
||||||
clientID,
|
clientID,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.GoogleIDPChangedEvent, error) {
|
) (*org.GoogleIDPChangedEvent, error) {
|
||||||
@ -777,7 +777,7 @@ func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
|||||||
userObjectClasses []string,
|
userObjectClasses []string,
|
||||||
userFilters []string,
|
userFilters []string,
|
||||||
timeout time.Duration,
|
timeout time.Duration,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
attributes idp.LDAPAttributes,
|
attributes idp.LDAPAttributes,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.LDAPIDPChangedEvent, error) {
|
) (*org.LDAPIDPChangedEvent, error) {
|
||||||
@ -858,7 +858,7 @@ func (wm *OrgAppleIDPWriteModel) NewChangedEvent(
|
|||||||
teamID,
|
teamID,
|
||||||
keyID string,
|
keyID string,
|
||||||
privateKey []byte,
|
privateKey []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
scopes []string,
|
scopes []string,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
) (*org.AppleIDPChangedEvent, error) {
|
) (*org.AppleIDPChangedEvent, error) {
|
||||||
@ -924,7 +924,7 @@ func (wm *OrgSAMLIDPWriteModel) NewChangedEvent(
|
|||||||
metadata,
|
metadata,
|
||||||
key,
|
key,
|
||||||
certificate []byte,
|
certificate []byte,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
binding string,
|
binding string,
|
||||||
withSignedRequest bool,
|
withSignedRequest bool,
|
||||||
options idp.Options,
|
options idp.Options,
|
||||||
|
@ -92,7 +92,7 @@ func (wm *IDPOIDCConfigWriteModel) NewChangedEvent(
|
|||||||
authorizationEndpoint,
|
authorizationEndpoint,
|
||||||
tokenEndpoint,
|
tokenEndpoint,
|
||||||
clientSecretString string,
|
clientSecretString string,
|
||||||
secretCrypto crypto.Crypto,
|
secretCrypto crypto.EncryptionAlgorithm,
|
||||||
idpDisplayNameMapping,
|
idpDisplayNameMapping,
|
||||||
userNameMapping domain.OIDCMappingField,
|
userNameMapping domain.OIDCMappingField,
|
||||||
scopes ...string,
|
scopes ...string,
|
||||||
|
@ -1260,7 +1260,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
keyAlgorithm crypto.EncryptionAlgorithm
|
keyAlgorithm crypto.EncryptionAlgorithm
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
@ -1437,7 +1437,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
ctx: authz.WithRequestedDomain(context.Background(), "iam-domain"),
|
||||||
@ -1616,7 +1616,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID", "tokenID"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "orgID", "userID", "tokenID"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
keyAlgorithm: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
@ -1671,7 +1671,7 @@ func TestCommandSide_SetUpOrg(t *testing.T) {
|
|||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore(t),
|
eventstore: tt.fields.eventstore(t),
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
keyAlgorithm: tt.fields.keyAlgorithm,
|
keyAlgorithm: tt.fields.keyAlgorithm,
|
||||||
zitadelRoles: []authz.RoleMapping{
|
zitadelRoles: []authz.RoleMapping{
|
||||||
{
|
{
|
||||||
|
@ -16,6 +16,6 @@ type Phone struct {
|
|||||||
ReturnCode bool
|
ReturnCode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) newPhoneCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) {
|
func (c *Commands) newPhoneCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return c.newCode(ctx, filter, domain.SecretGeneratorTypeVerifyPhoneCode, alg)
|
return c.newEncryptedCode(ctx, filter, domain.SecretGeneratorTypeVerifyPhoneCode, alg)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ type CommandVerifier interface {
|
|||||||
Validate(eventstore.Command) bool
|
Validate(eventstore.Command) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssertValidation checks if the validation works as inteded
|
// AssertValidation checks if the validation works as intended
|
||||||
func AssertValidation(t *testing.T, ctx context.Context, validation preparation.Validation, filter preparation.FilterToQueryReducer, want Want) {
|
func AssertValidation(t *testing.T, ctx context.Context, validation preparation.Validation, filter preparation.FilterToQueryReducer, want Want) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ func AssertValidation(t *testing.T, ctx context.Context, validation preparation.
|
|||||||
for i, cmd := range want.Commands {
|
for i, cmd := range want.Commands {
|
||||||
if v, ok := cmd.(CommandVerifier); ok {
|
if v, ok := cmd.(CommandVerifier); ok {
|
||||||
if verified := v.Validate(cmds[i]); !verified {
|
if verified := v.Validate(cmds[i]); !verified {
|
||||||
t.Errorf("verification failed on command: = %v, want %v", cmds[i], cmd)
|
t.Errorf("verification failed on command: =\n%v\nwant\n%v", cmds[i], cmd)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ package command
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/repository/project"
|
"github.com/zitadel/zitadel/internal/repository/project"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
@ -16,10 +14,6 @@ type AddApp struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) newAppClientSecret(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.HashAlgorithm) (*CryptoCode, error) {
|
|
||||||
return c.newCode(ctx, filter, domain.SecretGeneratorTypeAppSecret, alg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Commands) ChangeApplication(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (*domain.ObjectDetails, error) {
|
func (c *Commands) ChangeApplication(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||||
if projectID == "" || appChange.GetAppID() == "" || appChange.GetApplicationName() == "" {
|
if projectID == "" || appChange.GetAppID() == "" || appChange.GetApplicationName() == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.App.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.App.Invalid")
|
||||||
|
@ -4,10 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
project_repo "github.com/zitadel/zitadel/internal/repository/project"
|
project_repo "github.com/zitadel/zitadel/internal/repository/project"
|
||||||
@ -20,11 +17,11 @@ type addAPIApp struct {
|
|||||||
AuthMethodType domain.APIAuthMethodType
|
AuthMethodType domain.APIAuthMethodType
|
||||||
|
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
EncodedHash string
|
||||||
ClientSecretPlain string
|
ClientSecretPlain string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashAlgorithm) preparation.Validation {
|
func (c *Commands) AddAPIAppCommand(app *addAPIApp) preparation.Validation {
|
||||||
return func() (preparation.CreateCommands, error) {
|
return func() (preparation.CreateCommands, error) {
|
||||||
if app.ID == "" {
|
if app.ID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJE-XHsKt", "Errors.Invalid.Argument")
|
return nil, zerrors.ThrowInvalidArgument(nil, "PROJE-XHsKt", "Errors.Invalid.Argument")
|
||||||
@ -44,11 +41,10 @@ func (c *Commands) AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashA
|
|||||||
}
|
}
|
||||||
|
|
||||||
if app.AuthMethodType == domain.APIAuthMethodTypeBasic {
|
if app.AuthMethodType == domain.APIAuthMethodTypeBasic {
|
||||||
code, err := c.newAppClientSecret(ctx, filter, clientSecretAlg)
|
app.EncodedHash, app.ClientSecretPlain, err = c.newHashedSecret(ctx, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
app.ClientSecret, app.ClientSecretPlain = code.Crypted, code.Plain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []eventstore.Command{
|
return []eventstore.Command{
|
||||||
@ -63,7 +59,7 @@ func (c *Commands) AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashA
|
|||||||
&app.Aggregate.Aggregate,
|
&app.Aggregate.Aggregate,
|
||||||
app.ID,
|
app.ID,
|
||||||
app.ClientID,
|
app.ClientID,
|
||||||
app.ClientSecret,
|
app.EncodedHash,
|
||||||
app.AuthMethodType,
|
app.AuthMethodType,
|
||||||
),
|
),
|
||||||
}, nil
|
}, nil
|
||||||
@ -71,7 +67,7 @@ func (c *Commands) AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner, appID string, appSecretGenerator crypto.Generator) (_ *domain.APIApp, err error) {
|
func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner, appID string) (_ *domain.APIApp, err error) {
|
||||||
existingAPI, err := c.getAPIAppWriteModel(ctx, apiApp.AggregateID, appID, resourceOwner)
|
existingAPI, err := c.getAPIAppWriteModel(ctx, apiApp.AggregateID, appID, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -84,10 +80,10 @@ func (c *Commands) AddAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
|||||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsa", "Errors.Project.NotFound")
|
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-9fnsa", "Errors.Project.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID, appSecretGenerator)
|
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string, appSecretGenerator crypto.Generator) (_ *domain.APIApp, err error) {
|
func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string) (_ *domain.APIApp, err error) {
|
||||||
if apiApp == nil || apiApp.AggregateID == "" {
|
if apiApp == nil || apiApp.AggregateID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
||||||
}
|
}
|
||||||
@ -105,10 +101,10 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID, appSecretGenerator)
|
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, project, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner string, project *domain.Project, appID string, appSecretGenerator crypto.Generator) (_ *domain.APIApp, err error) {
|
func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.APIApp, resourceOwner string, project *domain.Project, appID string) (_ *domain.APIApp, err error) {
|
||||||
apiApp.AppID = appID
|
apiApp.AppID = appID
|
||||||
|
|
||||||
addedApplication := NewAPIApplicationWriteModel(apiApp.AggregateID, resourceOwner)
|
addedApplication := NewAPIApplicationWriteModel(apiApp.AggregateID, resourceOwner)
|
||||||
@ -118,12 +114,14 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
|||||||
project_repo.NewApplicationAddedEvent(ctx, projectAgg, apiApp.AppID, apiApp.AppName),
|
project_repo.NewApplicationAddedEvent(ctx, projectAgg, apiApp.AppID, apiApp.AppName),
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringPw string
|
var plain string
|
||||||
err = domain.SetNewClientID(apiApp, c.idGenerator, project)
|
err = domain.SetNewClientID(apiApp, c.idGenerator, project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stringPw, err = domain.SetNewClientSecretIfNeeded(apiApp, appSecretGenerator)
|
plain, err = domain.SetNewClientSecretIfNeeded(apiApp, func() (string, string, error) {
|
||||||
|
return c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -131,7 +129,7 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
|||||||
projectAgg,
|
projectAgg,
|
||||||
apiApp.AppID,
|
apiApp.AppID,
|
||||||
apiApp.ClientID,
|
apiApp.ClientID,
|
||||||
apiApp.ClientSecret,
|
apiApp.EncodedHash,
|
||||||
apiApp.AuthMethodType))
|
apiApp.AuthMethodType))
|
||||||
|
|
||||||
addedApplication.AppID = apiApp.AppID
|
addedApplication.AppID = apiApp.AppID
|
||||||
@ -144,7 +142,7 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result := apiWriteModelToAPIConfig(addedApplication)
|
result := apiWriteModelToAPIConfig(addedApplication)
|
||||||
result.ClientSecretString = stringPw
|
result.ClientSecretString = plain
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +186,7 @@ func (c *Commands) ChangeAPIApplication(ctx context.Context, apiApp *domain.APIA
|
|||||||
return apiWriteModelToAPIConfig(existingAPI), nil
|
return apiWriteModelToAPIConfig(existingAPI), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string, appSecretGenerator crypto.Generator) (*domain.APIApp, error) {
|
func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.APIApp, error) {
|
||||||
if projectID == "" || appID == "" {
|
if projectID == "" || appID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
|
||||||
}
|
}
|
||||||
@ -203,14 +201,14 @@ func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, ap
|
|||||||
if !existingAPI.IsAPI() {
|
if !existingAPI.IsAPI() {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-aeH4", "Errors.Project.App.IsNotAPI")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-aeH4", "Errors.Project.App.IsNotAPI")
|
||||||
}
|
}
|
||||||
cryptoSecret, stringPW, err := domain.NewClientSecret(appSecretGenerator)
|
encodedHash, plain, err := c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&existingAPI.WriteModel)
|
projectAgg := ProjectAggregateFromWriteModel(&existingAPI.WriteModel)
|
||||||
|
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, project_repo.NewAPIConfigSecretChangedEvent(ctx, projectAgg, appID, cryptoSecret))
|
pushedEvents, err := c.eventstore.Push(ctx, project_repo.NewAPIConfigSecretChangedEvent(ctx, projectAgg, appID, encodedHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -220,7 +218,7 @@ func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, ap
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := apiWriteModelToAPIConfig(existingAPI)
|
result := apiWriteModelToAPIConfig(existingAPI)
|
||||||
result.ClientSecretString = stringPW
|
result.ClientSecretString = plain
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,26 +231,35 @@ func (c *Commands) VerifyAPIClientSecret(ctx context.Context, projectID, appID,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !app.State.Exists() {
|
if !app.State.Exists() {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-DFnbf", "Errors.Project.App.NoExisting")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-DFnbf", "Errors.Project.App.NotExisting")
|
||||||
}
|
}
|
||||||
if !app.IsAPI() {
|
if !app.IsAPI() {
|
||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Bf3fw", "Errors.Project.App.IsNotAPI")
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Bf3fw", "Errors.Project.App.IsNotAPI")
|
||||||
}
|
}
|
||||||
if app.ClientSecret == nil {
|
if app.HashedSecret == "" {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D3t5g", "Errors.Project.App.APIConfigInvalid")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D3t5g", "Errors.Project.App.APIConfigInvalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
|
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
|
||||||
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash")
|
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
|
||||||
err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.codeAlg)
|
updated, err := c.secretHasher.Verify(app.HashedSecret, secret)
|
||||||
spanPasswordComparison.EndWithError(err)
|
spanPasswordComparison.EndWithError(err)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = c.eventstore.Push(ctx, project_repo.NewAPIConfigSecretCheckSucceededEvent(ctx, projectAgg, app.AppID))
|
c.apiSecretCheckSucceeded(ctx, projectAgg, app.AppID, updated)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = c.eventstore.Push(ctx, project_repo.NewAPIConfigSecretCheckFailedEvent(ctx, projectAgg, app.AppID))
|
c.apiSecretCheckFailed(ctx, projectAgg, app.AppID)
|
||||||
logging.Log("COMMAND-g3f12").OnError(err).Error("could not push event APIClientSecretCheckFailed")
|
return zerrors.ThrowInvalidArgument(err, "COMMAND-SADfg", "Errors.Project.App.ClientSecretInvalid")
|
||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-SADfg", "Errors.Project.App.ClientSecretInvalid")
|
}
|
||||||
|
|
||||||
|
func (c *Commands) APISecretCheckSucceeded(ctx context.Context, appID, projectID, resourceOwner, updated string) {
|
||||||
|
agg := project_repo.NewAggregate(projectID, resourceOwner)
|
||||||
|
c.apiSecretCheckSucceeded(ctx, &agg.Aggregate, appID, updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) APISecretCheckFailed(ctx context.Context, appID, projectID, resourceOwner string) {
|
||||||
|
agg := project_repo.NewAggregate(projectID, resourceOwner)
|
||||||
|
c.apiSecretCheckFailed(ctx, &agg.Aggregate, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) getAPIAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*APIApplicationWriteModel, error) {
|
func (c *Commands) getAPIAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*APIApplicationWriteModel, error) {
|
||||||
@ -263,3 +270,18 @@ func (c *Commands) getAPIAppWriteModel(ctx context.Context, projectID, appID, re
|
|||||||
}
|
}
|
||||||
return appWriteModel, nil
|
return appWriteModel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commands) apiSecretCheckSucceeded(ctx context.Context, agg *eventstore.Aggregate, appID, updated string) {
|
||||||
|
cmds := append(
|
||||||
|
make([]eventstore.Command, 0, 2),
|
||||||
|
project_repo.NewAPIConfigSecretCheckSucceededEvent(ctx, agg, appID),
|
||||||
|
)
|
||||||
|
if updated != "" {
|
||||||
|
cmds = append(cmds, project_repo.NewAPIConfigSecretHashUpdatedEvent(ctx, agg, appID, updated))
|
||||||
|
}
|
||||||
|
c.asyncPush(ctx, cmds...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) apiSecretCheckFailed(ctx context.Context, agg *eventstore.Aggregate, appID string) {
|
||||||
|
c.asyncPush(ctx, project_repo.NewAPIConfigSecretCheckFailedEvent(ctx, agg, appID))
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ type APIApplicationWriteModel struct {
|
|||||||
AppID string
|
AppID string
|
||||||
AppName string
|
AppName string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
HashedSecret string
|
||||||
ClientSecretString string
|
ClientSecretString string
|
||||||
AuthMethodType domain.APIAuthMethodType
|
AuthMethodType domain.APIAuthMethodType
|
||||||
State domain.AppState
|
State domain.AppState
|
||||||
@ -83,6 +83,11 @@ func (wm *APIApplicationWriteModel) AppendEvents(events ...eventstore.Event) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
|
case *project.APIConfigSecretHashUpdatedEvent:
|
||||||
|
if e.AppID != wm.AppID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wm.WriteModel.AppendEvents(e)
|
||||||
case *project.ProjectRemovedEvent:
|
case *project.ProjectRemovedEvent:
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
}
|
}
|
||||||
@ -114,7 +119,9 @@ func (wm *APIApplicationWriteModel) Reduce() error {
|
|||||||
case *project.APIConfigChangedEvent:
|
case *project.APIConfigChangedEvent:
|
||||||
wm.appendChangeAPIEvent(e)
|
wm.appendChangeAPIEvent(e)
|
||||||
case *project.APIConfigSecretChangedEvent:
|
case *project.APIConfigSecretChangedEvent:
|
||||||
wm.ClientSecret = e.ClientSecret
|
wm.HashedSecret = crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)
|
||||||
|
case *project.APIConfigSecretHashUpdatedEvent:
|
||||||
|
wm.HashedSecret = e.HashedSecret
|
||||||
case *project.ProjectRemovedEvent:
|
case *project.ProjectRemovedEvent:
|
||||||
wm.State = domain.AppStateRemoved
|
wm.State = domain.AppStateRemoved
|
||||||
}
|
}
|
||||||
@ -125,7 +132,7 @@ func (wm *APIApplicationWriteModel) Reduce() error {
|
|||||||
func (wm *APIApplicationWriteModel) appendAddAPIEvent(e *project.APIConfigAddedEvent) {
|
func (wm *APIApplicationWriteModel) appendAddAPIEvent(e *project.APIConfigAddedEvent) {
|
||||||
wm.api = true
|
wm.api = true
|
||||||
wm.ClientID = e.ClientID
|
wm.ClientID = e.ClientID
|
||||||
wm.ClientSecret = e.ClientSecret
|
wm.HashedSecret = crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)
|
||||||
wm.AuthMethodType = e.AuthMethodType
|
wm.AuthMethodType = e.AuthMethodType
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,8 +157,9 @@ func (wm *APIApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
project.APIConfigAddedType,
|
project.APIConfigAddedType,
|
||||||
project.APIConfigChangedType,
|
project.APIConfigChangedType,
|
||||||
project.APIConfigSecretChangedType,
|
project.APIConfigSecretChangedType,
|
||||||
project.ProjectRemovedType).
|
project.APIConfigSecretHashUpdatedType,
|
||||||
Builder()
|
project.ProjectRemovedType,
|
||||||
|
).Builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *APIApplicationWriteModel) NewChangedEvent(
|
func (wm *APIApplicationWriteModel) NewChangedEvent(
|
||||||
|
@ -2,9 +2,13 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zitadel/passwap"
|
||||||
|
"github.com/zitadel/passwap/bcrypt"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
@ -114,7 +118,7 @@ func TestAddAPIConfig(t *testing.T) {
|
|||||||
project.NewAPIConfigAddedEvent(ctx, &agg.Aggregate,
|
project.NewAPIConfigAddedEvent(ctx, &agg.Aggregate,
|
||||||
"appID",
|
"appID",
|
||||||
"clientID@project",
|
"clientID@project",
|
||||||
nil,
|
"",
|
||||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -137,7 +141,6 @@ func TestAddAPIConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
},
|
},
|
||||||
nil,
|
|
||||||
), tt.args.filter, tt.want)
|
), tt.args.filter, tt.want)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -145,14 +148,13 @@ func TestAddAPIConfig(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_AddAPIApplication(t *testing.T) {
|
func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
apiApp *domain.APIApp
|
apiApp *domain.APIApp
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
secretGenerator crypto.Generator
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.APIApp
|
want *domain.APIApp
|
||||||
@ -167,9 +169,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no aggregate id, invalid argument error",
|
name: "no aggregate id, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -183,8 +183,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "project not existing, not found error",
|
name: "project not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -206,8 +205,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid app, invalid argument error",
|
name: "invalid app, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -236,8 +234,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "create api app basic, ok",
|
name: "create api app basic, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -256,12 +253,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
domain.APIAuthMethodTypeBasic),
|
domain.APIAuthMethodTypeBasic),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -277,7 +269,6 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||||
},
|
},
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
secretGenerator: GetMockSecretGenerator(t),
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.APIApp{
|
want: &domain.APIApp{
|
||||||
@ -288,7 +279,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
AppID: "app1",
|
AppID: "app1",
|
||||||
AppName: "app",
|
AppName: "app",
|
||||||
ClientID: "client1@project",
|
ClientID: "client1@project",
|
||||||
ClientSecretString: "a",
|
ClientSecretString: "secret",
|
||||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
},
|
},
|
||||||
@ -297,8 +288,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "create api app jwt, ok",
|
name: "create api app jwt, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -317,7 +307,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
nil,
|
"",
|
||||||
domain.APIAuthMethodTypePrivateKeyJWT),
|
domain.APIAuthMethodTypePrivateKeyJWT),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -352,10 +342,14 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner, tt.args.secretGenerator)
|
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -371,7 +365,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -391,9 +385,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "missing appid, invalid argument error",
|
name: "missing appid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -414,9 +406,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "missing aggregateid, invalid argument error",
|
name: "missing aggregateid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -437,8 +427,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "app not existing, not found error",
|
name: "app not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -460,8 +449,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no changes, precondition error",
|
name: "no changes, precondition error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewApplicationAddedEvent(context.Background(),
|
project.NewApplicationAddedEvent(context.Background(),
|
||||||
@ -475,7 +463,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
nil,
|
"",
|
||||||
domain.APIAuthMethodTypePrivateKeyJWT),
|
domain.APIAuthMethodTypePrivateKeyJWT),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -500,8 +488,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "change api app, ok",
|
name: "change api app, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewApplicationAddedEvent(context.Background(),
|
project.NewApplicationAddedEvent(context.Background(),
|
||||||
@ -515,12 +502,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
domain.APIAuthMethodTypeBasic),
|
domain.APIAuthMethodTypeBasic),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -563,7 +545,11 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.ChangeAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
got, err := r.ChangeAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
@ -581,14 +567,13 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
appID string
|
appID string
|
||||||
projectID string
|
projectID string
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
secretGenerator crypto.Generator
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.APIApp
|
want *domain.APIApp
|
||||||
@ -603,9 +588,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no projectid, invalid argument error",
|
name: "no projectid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -619,9 +602,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no appid, invalid argument error",
|
name: "no appid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -636,8 +617,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "app not existing, not found error",
|
name: "app not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -654,8 +634,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "change secret, ok",
|
name: "change secret, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewApplicationAddedEvent(context.Background(),
|
project.NewApplicationAddedEvent(context.Background(),
|
||||||
@ -669,12 +648,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
domain.APIAuthMethodTypeBasic),
|
domain.APIAuthMethodTypeBasic),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -682,12 +656,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
project.NewAPIConfigSecretChangedEvent(context.Background(),
|
project.NewAPIConfigSecretChangedEvent(context.Background(),
|
||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -697,7 +666,6 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
projectID: "project1",
|
projectID: "project1",
|
||||||
appID: "app1",
|
appID: "app1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
secretGenerator: GetMockSecretGenerator(t),
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.APIApp{
|
want: &domain.APIApp{
|
||||||
@ -708,7 +676,7 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
AppID: "app1",
|
AppID: "app1",
|
||||||
AppName: "app",
|
AppName: "app",
|
||||||
ClientID: "client1@project",
|
ClientID: "client1@project",
|
||||||
ClientSecretString: "a",
|
ClientSecretString: "secret",
|
||||||
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
AuthMethodType: domain.APIAuthMethodTypeBasic,
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
},
|
},
|
||||||
@ -718,9 +686,13 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner, tt.args.secretGenerator)
|
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -745,3 +717,105 @@ func newAPIAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner
|
|||||||
)
|
)
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCommands_VerifyAPIClientSecret(t *testing.T) {
|
||||||
|
hasher := &crypto.Hasher{
|
||||||
|
Swapper: passwap.NewSwapper(bcrypt.New(bcrypt.MinCost)),
|
||||||
|
}
|
||||||
|
hashedSecret, err := hasher.Hash("secret")
|
||||||
|
require.NoError(t, err)
|
||||||
|
agg := project.NewAggregate("projectID", "orgID")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
secret string
|
||||||
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "filter error",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilterError(io.ErrClosedPipe),
|
||||||
|
),
|
||||||
|
wantErr: io.ErrClosedPipe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app not exists",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-DFnbf", "Errors.Project.App.NotExisting"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong app type",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowInvalidArgument(nil, "COMMAND-Bf3fw", "Errors.Project.App.IsNotAPI"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no secret set",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", "", domain.APIAuthMethodTypePrivateKeyJWT),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D3t5g", "Errors.Project.App.APIConfigInvalid"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "check succeeded",
|
||||||
|
secret: "secret",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", hashedSecret, domain.APIAuthMethodTypePrivateKeyJWT),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
project.NewAPIConfigSecretCheckSucceededEvent(context.Background(), &agg.Aggregate, "appID"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "check failed",
|
||||||
|
secret: "wrong!",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewAPIConfigAddedEvent(context.Background(), &agg.Aggregate, "appID", "clientID", hashedSecret, domain.APIAuthMethodTypePrivateKeyJWT),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
project.NewAPIConfigSecretCheckFailedEvent(context.Background(), &agg.Aggregate, "appID"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowInvalidArgument(err, "COMMAND-SADfg", "Errors.Project.App.ClientSecretInvalid"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := &Commands{
|
||||||
|
eventstore: tt.eventstore(t),
|
||||||
|
secretHasher: hasher,
|
||||||
|
}
|
||||||
|
err := c.VerifyAPIClientSecret(context.Background(), "projectID", "appID", tt.secret)
|
||||||
|
c.jobs.Wait()
|
||||||
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
@ -117,12 +116,7 @@ func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
domain.APIAuthMethodTypeBasic),
|
domain.APIAuthMethodTypeBasic),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -163,12 +157,7 @@ func TestCommandSide_AddAPIApplicationKey(t *testing.T) {
|
|||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
domain.APIAuthMethodTypeBasic),
|
domain.APIAuthMethodTypeBasic),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -5,11 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
project_repo "github.com/zitadel/zitadel/internal/repository/project"
|
project_repo "github.com/zitadel/zitadel/internal/repository/project"
|
||||||
@ -36,12 +33,12 @@ type addOIDCApp struct {
|
|||||||
SkipSuccessPageForNativeApp bool
|
SkipSuccessPageForNativeApp bool
|
||||||
|
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
ClientSecret string
|
||||||
ClientSecretPlain string
|
ClientSecretPlain string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOIDCAppCommand prepares the commands to add an oidc app. The ClientID will be set during the CreateCommands
|
// AddOIDCAppCommand prepares the commands to add an oidc app. The ClientID will be set during the CreateCommands
|
||||||
func (c *Commands) AddOIDCAppCommand(app *addOIDCApp, clientSecretAlg crypto.HashAlgorithm) preparation.Validation {
|
func (c *Commands) AddOIDCAppCommand(app *addOIDCApp) preparation.Validation {
|
||||||
return func() (preparation.CreateCommands, error) {
|
return func() (preparation.CreateCommands, error) {
|
||||||
if app.ID == "" {
|
if app.ID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJE-NnavI", "Errors.Invalid.Argument")
|
return nil, zerrors.ThrowInvalidArgument(nil, "PROJE-NnavI", "Errors.Invalid.Argument")
|
||||||
@ -77,11 +74,10 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp, clientSecretAlg crypto.Has
|
|||||||
}
|
}
|
||||||
|
|
||||||
if app.AuthMethodType == domain.OIDCAuthMethodTypeBasic || app.AuthMethodType == domain.OIDCAuthMethodTypePost {
|
if app.AuthMethodType == domain.OIDCAuthMethodTypeBasic || app.AuthMethodType == domain.OIDCAuthMethodTypePost {
|
||||||
code, err := c.newAppClientSecret(ctx, filter, clientSecretAlg)
|
app.ClientSecret, app.ClientSecretPlain, err = c.newHashedSecret(ctx, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
app.ClientSecret, app.ClientSecretPlain = code.Crypted, code.Plain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []eventstore.Command{
|
return []eventstore.Command{
|
||||||
@ -118,7 +114,7 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp, clientSecretAlg crypto.Has
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner, appID string, appSecretGenerator crypto.Generator) (_ *domain.OIDCApp, err error) {
|
func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner, appID string) (_ *domain.OIDCApp, err error) {
|
||||||
existingApp, err := c.getOIDCAppWriteModel(ctx, oidcApp.AggregateID, appID, resourceOwner)
|
existingApp, err := c.getOIDCAppWriteModel(ctx, oidcApp.AggregateID, appID, resourceOwner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -132,10 +128,10 @@ func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
|||||||
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound")
|
return nil, zerrors.ThrowPreconditionFailed(err, "PROJECT-3m9s2", "Errors.Project.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID, appSecretGenerator)
|
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, appSecretGenerator crypto.Generator) (_ *domain.OIDCApp, err error) {
|
func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string) (_ *domain.OIDCApp, err error) {
|
||||||
if oidcApp == nil || oidcApp.AggregateID == "" {
|
if oidcApp == nil || oidcApp.AggregateID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
||||||
}
|
}
|
||||||
@ -153,11 +149,10 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID, appSecretGenerator)
|
return c.addOIDCApplicationWithID(ctx, oidcApp, resourceOwner, project, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, project *domain.Project, appID string, appSecretGenerator crypto.Generator) (_ *domain.OIDCApp, err error) {
|
func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner string, project *domain.Project, appID string) (_ *domain.OIDCApp, err error) {
|
||||||
|
|
||||||
addedApplication := NewOIDCApplicationWriteModel(oidcApp.AggregateID, resourceOwner)
|
addedApplication := NewOIDCApplicationWriteModel(oidcApp.AggregateID, resourceOwner)
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||||
|
|
||||||
@ -167,12 +162,14 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
|||||||
project_repo.NewApplicationAddedEvent(ctx, projectAgg, oidcApp.AppID, oidcApp.AppName),
|
project_repo.NewApplicationAddedEvent(ctx, projectAgg, oidcApp.AppID, oidcApp.AppName),
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringPw string
|
var plain string
|
||||||
err = domain.SetNewClientID(oidcApp, c.idGenerator, project)
|
err = domain.SetNewClientID(oidcApp, c.idGenerator, project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
stringPw, err = domain.SetNewClientSecretIfNeeded(oidcApp, appSecretGenerator)
|
plain, err = domain.SetNewClientSecretIfNeeded(oidcApp, func() (string, string, error) {
|
||||||
|
return c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -181,7 +178,7 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
|||||||
oidcApp.OIDCVersion,
|
oidcApp.OIDCVersion,
|
||||||
oidcApp.AppID,
|
oidcApp.AppID,
|
||||||
oidcApp.ClientID,
|
oidcApp.ClientID,
|
||||||
oidcApp.ClientSecret,
|
oidcApp.EncodedHash,
|
||||||
trimStringSliceWhiteSpaces(oidcApp.RedirectUris),
|
trimStringSliceWhiteSpaces(oidcApp.RedirectUris),
|
||||||
oidcApp.ResponseTypes,
|
oidcApp.ResponseTypes,
|
||||||
oidcApp.GrantTypes,
|
oidcApp.GrantTypes,
|
||||||
@ -208,7 +205,7 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result := oidcWriteModelToOIDCConfig(addedApplication)
|
result := oidcWriteModelToOIDCConfig(addedApplication)
|
||||||
result.ClientSecretString = stringPw
|
result.ClientSecretString = plain
|
||||||
result.FillCompliance()
|
result.FillCompliance()
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@ -270,7 +267,7 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string, appSecretGenerator crypto.Generator) (*domain.OIDCApp, error) {
|
func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.OIDCApp, error) {
|
||||||
if projectID == "" || appID == "" {
|
if projectID == "" || appID == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-99i83", "Errors.IDMissing")
|
||||||
}
|
}
|
||||||
@ -285,14 +282,14 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a
|
|||||||
if !existingOIDC.IsOIDC() {
|
if !existingOIDC.IsOIDC() {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC")
|
||||||
}
|
}
|
||||||
cryptoSecret, stringPW, err := domain.NewClientSecret(appSecretGenerator)
|
encodedHash, plain, err := c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
|
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
|
||||||
|
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretChangedEvent(ctx, projectAgg, appID, cryptoSecret))
|
pushedEvents, err := c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretChangedEvent(ctx, projectAgg, appID, encodedHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -302,7 +299,7 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := oidcWriteModelToOIDCConfig(existingOIDC)
|
result := oidcWriteModelToOIDCConfig(existingOIDC)
|
||||||
result.ClientSecretString = stringPW
|
result.ClientSecretString = plain
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,26 +312,35 @@ func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !app.State.Exists() {
|
if !app.State.Exists() {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NotExisting")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D8hba", "Errors.Project.App.NotExisting")
|
||||||
}
|
}
|
||||||
if !app.IsOIDC() {
|
if !app.IsOIDC() {
|
||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC")
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC")
|
||||||
}
|
}
|
||||||
if app.ClientSecret == nil {
|
if app.HashedSecret == "" {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
|
projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel)
|
||||||
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash")
|
ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "passwap.Verify")
|
||||||
err = crypto.CompareHash(app.ClientSecret, []byte(secret), c.codeAlg)
|
updated, err := c.secretHasher.Verify(app.HashedSecret, secret)
|
||||||
spanPasswordComparison.EndWithError(err)
|
spanPasswordComparison.EndWithError(err)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretCheckSucceededEvent(ctx, projectAgg, app.AppID))
|
c.oidcSecretCheckSucceeded(ctx, projectAgg, appID, updated)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
_, err = c.eventstore.Push(ctx, project_repo.NewOIDCConfigSecretCheckFailedEvent(ctx, projectAgg, app.AppID))
|
c.oidcSecretCheckFailed(ctx, projectAgg, appID)
|
||||||
logging.OnError(err).Error("could not push event OIDCClientSecretCheckFailed")
|
return zerrors.ThrowInvalidArgument(err, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid")
|
||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid")
|
}
|
||||||
|
|
||||||
|
func (c *Commands) OIDCSecretCheckSucceeded(ctx context.Context, appID, projectID, resourceOwner, updated string) {
|
||||||
|
agg := project_repo.NewAggregate(projectID, resourceOwner)
|
||||||
|
c.oidcSecretCheckSucceeded(ctx, &agg.Aggregate, appID, updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) OIDCSecretCheckFailed(ctx context.Context, appID, projectID, resourceOwner string) {
|
||||||
|
agg := project_repo.NewAggregate(projectID, resourceOwner)
|
||||||
|
c.oidcSecretCheckFailed(ctx, &agg.Aggregate, appID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) getOIDCAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*OIDCApplicationWriteModel, error) {
|
func (c *Commands) getOIDCAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*OIDCApplicationWriteModel, error) {
|
||||||
@ -366,3 +372,18 @@ func trimStringSliceWhiteSpaces(slice []string) []string {
|
|||||||
}
|
}
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commands) oidcSecretCheckSucceeded(ctx context.Context, agg *eventstore.Aggregate, appID, updated string) {
|
||||||
|
cmds := append(
|
||||||
|
make([]eventstore.Command, 0, 2),
|
||||||
|
project_repo.NewOIDCConfigSecretCheckSucceededEvent(ctx, agg, appID),
|
||||||
|
)
|
||||||
|
if updated != "" {
|
||||||
|
cmds = append(cmds, project_repo.NewOIDCConfigSecretHashUpdatedEvent(ctx, agg, appID, updated))
|
||||||
|
}
|
||||||
|
c.asyncPush(ctx, cmds...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Commands) oidcSecretCheckFailed(ctx context.Context, agg *eventstore.Aggregate, appID string) {
|
||||||
|
c.asyncPush(ctx, project_repo.NewOIDCConfigSecretCheckFailedEvent(ctx, agg, appID))
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ type OIDCApplicationWriteModel struct {
|
|||||||
AppID string
|
AppID string
|
||||||
AppName string
|
AppName string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
HashedSecret string
|
||||||
ClientSecretString string
|
ClientSecretString string
|
||||||
RedirectUris []string
|
RedirectUris []string
|
||||||
ResponseTypes []domain.OIDCResponseType
|
ResponseTypes []domain.OIDCResponseType
|
||||||
@ -100,6 +100,11 @@ func (wm *OIDCApplicationWriteModel) AppendEvents(events ...eventstore.Event) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
|
case *project.OIDCConfigSecretHashUpdatedEvent:
|
||||||
|
if e.AppID != wm.AppID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wm.WriteModel.AppendEvents(e)
|
||||||
case *project.ProjectRemovedEvent:
|
case *project.ProjectRemovedEvent:
|
||||||
wm.WriteModel.AppendEvents(e)
|
wm.WriteModel.AppendEvents(e)
|
||||||
}
|
}
|
||||||
@ -131,7 +136,9 @@ func (wm *OIDCApplicationWriteModel) Reduce() error {
|
|||||||
case *project.OIDCConfigChangedEvent:
|
case *project.OIDCConfigChangedEvent:
|
||||||
wm.appendChangeOIDCEvent(e)
|
wm.appendChangeOIDCEvent(e)
|
||||||
case *project.OIDCConfigSecretChangedEvent:
|
case *project.OIDCConfigSecretChangedEvent:
|
||||||
wm.ClientSecret = e.ClientSecret
|
wm.HashedSecret = crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)
|
||||||
|
case *project.OIDCConfigSecretHashUpdatedEvent:
|
||||||
|
wm.HashedSecret = e.HashedSecret
|
||||||
case *project.ProjectRemovedEvent:
|
case *project.ProjectRemovedEvent:
|
||||||
wm.State = domain.AppStateRemoved
|
wm.State = domain.AppStateRemoved
|
||||||
}
|
}
|
||||||
@ -142,7 +149,7 @@ func (wm *OIDCApplicationWriteModel) Reduce() error {
|
|||||||
func (wm *OIDCApplicationWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAddedEvent) {
|
func (wm *OIDCApplicationWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAddedEvent) {
|
||||||
wm.oidc = true
|
wm.oidc = true
|
||||||
wm.ClientID = e.ClientID
|
wm.ClientID = e.ClientID
|
||||||
wm.ClientSecret = e.ClientSecret
|
wm.HashedSecret = crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)
|
||||||
wm.RedirectUris = e.RedirectUris
|
wm.RedirectUris = e.RedirectUris
|
||||||
wm.ResponseTypes = e.ResponseTypes
|
wm.ResponseTypes = e.ResponseTypes
|
||||||
wm.GrantTypes = e.GrantTypes
|
wm.GrantTypes = e.GrantTypes
|
||||||
@ -223,8 +230,9 @@ func (wm *OIDCApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
project.OIDCConfigAddedType,
|
project.OIDCConfigAddedType,
|
||||||
project.OIDCConfigChangedType,
|
project.OIDCConfigChangedType,
|
||||||
project.OIDCConfigSecretChangedType,
|
project.OIDCConfigSecretChangedType,
|
||||||
project.ProjectRemovedType).
|
project.OIDCConfigSecretHashUpdatedType,
|
||||||
Builder()
|
project.ProjectRemovedType,
|
||||||
|
).Builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
||||||
|
@ -2,10 +2,14 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zitadel/passwap"
|
||||||
|
"github.com/zitadel/passwap/bcrypt"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
@ -24,7 +28,6 @@ func TestAddOIDCApp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
app *addOIDCApp
|
app *addOIDCApp
|
||||||
clientSecretAlg crypto.HashAlgorithm
|
|
||||||
filter preparation.FilterToQueryReducer
|
filter preparation.FilterToQueryReducer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +159,7 @@ func TestAddOIDCApp(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"id",
|
"id",
|
||||||
"clientID@project",
|
"clientID@project",
|
||||||
nil,
|
"",
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -221,7 +224,7 @@ func TestAddOIDCApp(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"id",
|
"id",
|
||||||
"clientID@project",
|
"clientID@project",
|
||||||
nil,
|
"",
|
||||||
nil,
|
nil,
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -240,17 +243,85 @@ func TestAddOIDCApp(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "with secret",
|
||||||
|
fields: fields{
|
||||||
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "clientID"),
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
app: &addOIDCApp{
|
||||||
|
AddApp: AddApp{
|
||||||
|
Aggregate: *agg,
|
||||||
|
ID: "id",
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
|
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
Version: domain.OIDCVersionV1,
|
||||||
|
|
||||||
|
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||||
|
AuthMethodType: domain.OIDCAuthMethodTypeBasic,
|
||||||
|
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||||
|
},
|
||||||
|
filter: NewMultiFilter().
|
||||||
|
Append(func(ctx context.Context, queryFactory *eventstore.SearchQueryBuilder) ([]eventstore.Event, error) {
|
||||||
|
return []eventstore.Event{
|
||||||
|
project.NewProjectAddedEvent(
|
||||||
|
ctx,
|
||||||
|
&agg.Aggregate,
|
||||||
|
"project",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
domain.PrivateLabelingSettingUnspecified,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}).
|
||||||
|
Filter(),
|
||||||
|
},
|
||||||
|
want: Want{
|
||||||
|
Commands: []eventstore.Command{
|
||||||
|
project.NewApplicationAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
project.NewOIDCConfigAddedEvent(ctx, &agg.Aggregate,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"id",
|
||||||
|
"clientID@project",
|
||||||
|
"secret",
|
||||||
|
nil,
|
||||||
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypeBasic,
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := Commands{
|
c := Commands{
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
AssertValidation(t,
|
AssertValidation(t,
|
||||||
context.Background(),
|
context.Background(),
|
||||||
c.AddOIDCAppCommand(
|
c.AddOIDCAppCommand(
|
||||||
tt.args.app,
|
tt.args.app,
|
||||||
tt.args.clientSecretAlg,
|
|
||||||
), tt.args.filter, tt.want)
|
), tt.args.filter, tt.want)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -258,14 +329,13 @@ func TestAddOIDCApp(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
oidcApp *domain.OIDCApp
|
oidcApp *domain.OIDCApp
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
secretGenerator crypto.Generator
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.OIDCApp
|
want *domain.OIDCApp
|
||||||
@ -280,9 +350,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no aggregate id, invalid argument error",
|
name: "no aggregate id, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -296,8 +364,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "project not existing, not found error",
|
name: "project not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -319,8 +386,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "invalid app, invalid argument error",
|
name: "invalid app, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -349,8 +415,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "create oidc app basic using whitespaces in uris, ok",
|
name: "create oidc app basic using whitespaces in uris, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -370,12 +435,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -419,7 +479,6 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
SkipNativeAppSuccessPage: true,
|
SkipNativeAppSuccessPage: true,
|
||||||
},
|
},
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
secretGenerator: GetMockSecretGenerator(t),
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.OIDCApp{
|
want: &domain.OIDCApp{
|
||||||
@ -430,7 +489,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
AppID: "app1",
|
AppID: "app1",
|
||||||
AppName: "app",
|
AppName: "app",
|
||||||
ClientID: "client1@project",
|
ClientID: "client1@project",
|
||||||
ClientSecretString: "a",
|
ClientSecretString: "secret",
|
||||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||||
OIDCVersion: domain.OIDCVersionV1,
|
OIDCVersion: domain.OIDCVersionV1,
|
||||||
RedirectUris: []string{"https://test.ch"},
|
RedirectUris: []string{"https://test.ch"},
|
||||||
@ -454,8 +513,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "create oidc app basic, ok",
|
name: "create oidc app basic, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewProjectAddedEvent(context.Background(),
|
project.NewProjectAddedEvent(context.Background(),
|
||||||
@ -475,12 +533,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -524,7 +577,6 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
SkipNativeAppSuccessPage: true,
|
SkipNativeAppSuccessPage: true,
|
||||||
},
|
},
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
secretGenerator: GetMockSecretGenerator(t),
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.OIDCApp{
|
want: &domain.OIDCApp{
|
||||||
@ -535,7 +587,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
AppID: "app1",
|
AppID: "app1",
|
||||||
AppName: "app",
|
AppName: "app",
|
||||||
ClientID: "client1@project",
|
ClientID: "client1@project",
|
||||||
ClientSecretString: "a",
|
ClientSecretString: "secret",
|
||||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||||
OIDCVersion: domain.OIDCVersionV1,
|
OIDCVersion: domain.OIDCVersionV1,
|
||||||
RedirectUris: []string{"https://test.ch"},
|
RedirectUris: []string{"https://test.ch"},
|
||||||
@ -560,10 +612,14 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.AddOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner, tt.args.secretGenerator)
|
got, err := r.AddOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -709,12 +765,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -783,12 +834,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -857,12 +903,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -965,14 +1006,13 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
appID string
|
appID string
|
||||||
projectID string
|
projectID string
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
secretGenerator crypto.Generator
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *domain.OIDCApp
|
want *domain.OIDCApp
|
||||||
@ -987,9 +1027,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no projectid, invalid argument error",
|
name: "no projectid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1003,9 +1041,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "no appid, invalid argument error",
|
name: "no appid, invalid argument error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1020,8 +1056,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "app not existing, not found error",
|
name: "app not existing, not found error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1038,8 +1073,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "change secret, ok",
|
name: "change secret, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
project.NewApplicationAddedEvent(context.Background(),
|
project.NewApplicationAddedEvent(context.Background(),
|
||||||
@ -1054,12 +1088,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"app1",
|
"app1",
|
||||||
"client1@project",
|
"client1@project",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
[]string{"https://test.ch"},
|
[]string{"https://test.ch"},
|
||||||
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -1081,12 +1110,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
project.NewOIDCConfigSecretChangedEvent(context.Background(),
|
project.NewOIDCConfigSecretChangedEvent(context.Background(),
|
||||||
&project.NewAggregate("project1", "org1").Aggregate,
|
&project.NewAggregate("project1", "org1").Aggregate,
|
||||||
"app1",
|
"app1",
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1096,7 +1120,6 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
projectID: "project1",
|
projectID: "project1",
|
||||||
appID: "app1",
|
appID: "app1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
secretGenerator: GetMockSecretGenerator(t),
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
want: &domain.OIDCApp{
|
want: &domain.OIDCApp{
|
||||||
@ -1107,7 +1130,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
AppID: "app1",
|
AppID: "app1",
|
||||||
AppName: "app",
|
AppName: "app",
|
||||||
ClientID: "client1@project",
|
ClientID: "client1@project",
|
||||||
ClientSecretString: "a",
|
ClientSecretString: "secret",
|
||||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||||
OIDCVersion: domain.OIDCVersionV1,
|
OIDCVersion: domain.OIDCVersionV1,
|
||||||
RedirectUris: []string{"https://test.ch"},
|
RedirectUris: []string{"https://test.ch"},
|
||||||
@ -1129,11 +1152,15 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(*testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.ChangeOIDCApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner, tt.args.secretGenerator)
|
got, err := r.ChangeOIDCApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -1165,3 +1192,165 @@ func newOIDCAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner
|
|||||||
)
|
)
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCommands_VerifyOIDCClientSecret(t *testing.T) {
|
||||||
|
hasher := &crypto.Hasher{
|
||||||
|
Swapper: passwap.NewSwapper(bcrypt.New(bcrypt.MinCost)),
|
||||||
|
}
|
||||||
|
hashedSecret, err := hasher.Hash("secret")
|
||||||
|
require.NoError(t, err)
|
||||||
|
agg := project.NewAggregate("projectID", "orgID")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
secret string
|
||||||
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
|
wantErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "filter error",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilterError(io.ErrClosedPipe),
|
||||||
|
),
|
||||||
|
wantErr: io.ErrClosedPipe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app not exists",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D8hba", "Errors.Project.App.NotExisting"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wrong app type",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no secret set",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&agg.Aggregate,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"appID",
|
||||||
|
"client1@project",
|
||||||
|
"",
|
||||||
|
[]string{"https://test.ch"},
|
||||||
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypePost,
|
||||||
|
[]string{"https://test.ch/logout"},
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
time.Second*1,
|
||||||
|
[]string{"https://sub.test.ch"},
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "check succeeded",
|
||||||
|
secret: "secret",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&agg.Aggregate,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"appID",
|
||||||
|
"client1@project",
|
||||||
|
hashedSecret,
|
||||||
|
[]string{"https://test.ch"},
|
||||||
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypePost,
|
||||||
|
[]string{"https://test.ch/logout"},
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
time.Second*1,
|
||||||
|
[]string{"https://sub.test.ch"},
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
project.NewOIDCConfigSecretCheckSucceededEvent(context.Background(), &agg.Aggregate, "appID"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "check failed",
|
||||||
|
secret: "wrong!",
|
||||||
|
eventstore: expectEventstore(
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewApplicationAddedEvent(context.Background(), &agg.Aggregate, "appID", "appName"),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
project.NewOIDCConfigAddedEvent(context.Background(),
|
||||||
|
&agg.Aggregate,
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"appID",
|
||||||
|
"client1@project",
|
||||||
|
hashedSecret,
|
||||||
|
[]string{"https://test.ch"},
|
||||||
|
[]domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
|
[]domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
|
domain.OIDCApplicationTypeWeb,
|
||||||
|
domain.OIDCAuthMethodTypePost,
|
||||||
|
[]string{"https://test.ch/logout"},
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeBearer,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
time.Second*1,
|
||||||
|
[]string{"https://sub.test.ch"},
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectPush(
|
||||||
|
project.NewOIDCConfigSecretCheckFailedEvent(context.Background(), &agg.Aggregate, "appID"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
wantErr: zerrors.ThrowInvalidArgument(err, "COMMAND-Bz542", "Errors.Project.App.ClientSecretInvalid"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := &Commands{
|
||||||
|
eventstore: tt.eventstore(t),
|
||||||
|
secretHasher: hasher,
|
||||||
|
}
|
||||||
|
err := c.VerifyOIDCClientSecret(context.Background(), "projectID", "appID", tt.secret)
|
||||||
|
c.jobs.Wait()
|
||||||
|
require.ErrorIs(t, err, tt.wantErr)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,11 +31,11 @@ type SessionCommands struct {
|
|||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
eventCommands []eventstore.Command
|
eventCommands []eventstore.Command
|
||||||
|
|
||||||
hasher *crypto.PasswordHasher
|
hasher *crypto.Hasher
|
||||||
intentAlg crypto.EncryptionAlgorithm
|
intentAlg crypto.EncryptionAlgorithm
|
||||||
totpAlg crypto.EncryptionAlgorithm
|
totpAlg crypto.EncryptionAlgorithm
|
||||||
otpAlg crypto.EncryptionAlgorithm
|
otpAlg crypto.EncryptionAlgorithm
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
createToken func(sessionID string) (id string, token string, err error)
|
createToken func(sessionID string) (id string, token string, err error)
|
||||||
now func() time.Time
|
now func() time.Time
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ func (c *Commands) NewSessionCommands(cmds []SessionCommand, session *SessionWri
|
|||||||
intentAlg: c.idpConfigEncryption,
|
intentAlg: c.idpConfigEncryption,
|
||||||
totpAlg: c.multifactors.OTP.CryptoMFA,
|
totpAlg: c.multifactors.OTP.CryptoMFA,
|
||||||
otpAlg: c.userEncryption,
|
otpAlg: c.userEncryption,
|
||||||
createCode: c.newCodeWithDefault,
|
createCode: c.newEncryptedCodeWithDefault,
|
||||||
createToken: c.sessionTokenCreator,
|
createToken: c.sessionTokenCreator,
|
||||||
now: time.Now,
|
now: time.Now,
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ func CheckOTPSMS(code string) SessionCommand {
|
|||||||
if challenge == nil {
|
if challenge == nil {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SF3tv", "Errors.User.Code.NotFound")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SF3tv", "Errors.User.Code.NotFound")
|
||||||
}
|
}
|
||||||
err = crypto.VerifyCodeWithAlgorithm(challenge.CreationDate, challenge.Expiry, challenge.Code, code, cmd.otpAlg)
|
err = crypto.VerifyCode(challenge.CreationDate, challenge.Expiry, challenge.Code, code, cmd.otpAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ func CheckOTPEmail(code string) SessionCommand {
|
|||||||
if challenge == nil {
|
if challenge == nil {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-zF3g3", "Errors.User.Code.NotFound")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-zF3g3", "Errors.User.Code.NotFound")
|
||||||
}
|
}
|
||||||
err = crypto.VerifyCodeWithAlgorithm(challenge.CreationDate, challenge.Expiry, challenge.Code, code, cmd.otpAlg)
|
err = crypto.VerifyCode(challenge.CreationDate, challenge.Expiry, challenge.Code, code, cmd.otpAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func TestCommands_CreateOTPSMSChallengeReturnCode(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
userID string
|
userID string
|
||||||
eventstore func(*testing.T) *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
err error
|
err error
|
||||||
@ -65,7 +65,7 @@ func TestCommands_CreateOTPSMSChallengeReturnCode(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
createCode: mockCodeWithDefault("1234567", 5*time.Minute),
|
createCode: mockEncryptedCodeWithDefault("1234567", 5*time.Minute),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
returnCode: "1234567",
|
returnCode: "1234567",
|
||||||
@ -122,7 +122,7 @@ func TestCommands_CreateOTPSMSChallenge(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
userID string
|
userID string
|
||||||
eventstore func(*testing.T) *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
err error
|
err error
|
||||||
@ -166,7 +166,7 @@ func TestCommands_CreateOTPSMSChallenge(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
createCode: mockCodeWithDefault("1234567", 5*time.Minute),
|
createCode: mockEncryptedCodeWithDefault("1234567", 5*time.Minute),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
commands: []eventstore.Command{
|
commands: []eventstore.Command{
|
||||||
@ -292,7 +292,7 @@ func TestCommands_CreateOTPEmailChallengeURLTemplate(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
userID string
|
userID string
|
||||||
eventstore func(*testing.T) *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
urlTmpl string
|
urlTmpl string
|
||||||
@ -361,7 +361,7 @@ func TestCommands_CreateOTPEmailChallengeURLTemplate(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
createCode: mockCodeWithDefault("1234567", 5*time.Minute),
|
createCode: mockEncryptedCodeWithDefault("1234567", 5*time.Minute),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
commands: []eventstore.Command{
|
commands: []eventstore.Command{
|
||||||
@ -421,7 +421,7 @@ func TestCommands_CreateOTPEmailChallengeReturnCode(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
userID string
|
userID string
|
||||||
eventstore func(*testing.T) *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
err error
|
err error
|
||||||
@ -465,7 +465,7 @@ func TestCommands_CreateOTPEmailChallengeReturnCode(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
createCode: mockCodeWithDefault("1234567", 5*time.Minute),
|
createCode: mockEncryptedCodeWithDefault("1234567", 5*time.Minute),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
returnCode: "1234567",
|
returnCode: "1234567",
|
||||||
@ -523,7 +523,7 @@ func TestCommands_CreateOTPEmailChallenge(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
userID string
|
userID string
|
||||||
eventstore func(*testing.T) *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
createCode cryptoCodeWithDefaultFunc
|
createCode encryptedCodeWithDefaultFunc
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
err error
|
err error
|
||||||
@ -566,7 +566,7 @@ func TestCommands_CreateOTPEmailChallenge(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
createCode: mockCodeWithDefault("1234567", 5*time.Minute),
|
createCode: mockEncryptedCodeWithDefault("1234567", 5*time.Minute),
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
commands: []eventstore.Command{
|
commands: []eventstore.Command{
|
||||||
|
@ -476,8 +476,8 @@ func ExistsUser(ctx context.Context, filter preparation.FilterToQueryReducer, id
|
|||||||
return exists, nil
|
return exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) {
|
func (c *Commands) newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return c.newCode(ctx, filter, domain.SecretGeneratorTypeInitCode, alg)
|
return c.newEncryptedCode(ctx, filter, domain.SecretGeneratorTypeInitCode, alg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func userWriteModelByID(ctx context.Context, filter preparation.FilterToQueryReducer, userID, resourceOwner string) (*UserWriteModel, error) {
|
func userWriteModelByID(ctx context.Context, filter preparation.FilterToQueryReducer, userID, resourceOwner string) (*UserWriteModel, error) {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
"github.com/zitadel/zitadel/internal/repository/user"
|
||||||
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ type AddLink struct {
|
|||||||
IDPExternalID string
|
IDPExternalID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AddHuman) Validate(hasher *crypto.PasswordHasher) (err error) {
|
func (h *AddHuman) Validate(hasher *crypto.Hasher) (err error) {
|
||||||
if err := h.Email.Validate(); err != nil {
|
if err := h.Email.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -164,7 +165,7 @@ type humanCreationCommand interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocognit
|
//nolint:gocognit
|
||||||
func (c *Commands) AddHumanCommand(human *AddHuman, orgID string, hasher *crypto.PasswordHasher, codeAlg crypto.EncryptionAlgorithm, allowInitMail bool) preparation.Validation {
|
func (c *Commands) AddHumanCommand(human *AddHuman, orgID string, hasher *crypto.Hasher, codeAlg crypto.EncryptionAlgorithm, allowInitMail bool) preparation.Validation {
|
||||||
return func() (_ preparation.CreateCommands, err error) {
|
return func() (_ preparation.CreateCommands, err error) {
|
||||||
if err := human.Validate(hasher); err != nil {
|
if err := human.Validate(hasher); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -329,17 +330,19 @@ func (c *Commands) addHumanCommandCheckID(ctx context.Context, filter preparatio
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQueryReducer, createCmd humanCreationCommand, human *AddHuman, hasher *crypto.PasswordHasher) (err error) {
|
func addHumanCommandPassword(ctx context.Context, filter preparation.FilterToQueryReducer, createCmd humanCreationCommand, human *AddHuman, hasher *crypto.Hasher) (err error) {
|
||||||
if human.Password != "" {
|
if human.Password != "" {
|
||||||
if err = humanValidatePassword(ctx, filter, human.Password); err != nil {
|
if err = humanValidatePassword(ctx, filter, human.Password); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
secret, err := hasher.Hash(human.Password)
|
_, spanHash := tracing.NewNamedSpan(ctx, "passwap.Hash")
|
||||||
|
encodedHash, err := hasher.Hash(human.Password)
|
||||||
|
spanHash.EndWithError(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
createCmd.AddPasswordData(secret, human.PasswordChangeRequired)
|
createCmd.AddPasswordData(encodedHash, human.PasswordChangeRequired)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,7 +592,7 @@ func (c *Commands) createHuman(ctx context.Context, orgID string, human *domain.
|
|||||||
|
|
||||||
human.EnsureDisplayName()
|
human.EnsureDisplayName()
|
||||||
if human.Password != nil {
|
if human.Password != nil {
|
||||||
if err := human.HashPasswordIfExisting(pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil {
|
if err := human.HashPasswordIfExisting(ctx, pwPolicy, c.userPasswordHasher, human.Password.ChangeRequired); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ func (c *Commands) VerifyHumanEmail(ctx context.Context, userID, code, resourceo
|
|||||||
}
|
}
|
||||||
|
|
||||||
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
||||||
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, emailCodeGenerator)
|
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, emailCodeGenerator.Alg())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
|
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanEmailVerifiedEvent(ctx, userAgg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -67,7 +67,7 @@ func (c *Commands) HumanVerifyInitCode(ctx context.Context, userID, resourceOwne
|
|||||||
}
|
}
|
||||||
|
|
||||||
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
||||||
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, initCodeGenerator)
|
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, initCodeGenerator.Alg())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = c.eventstore.Push(ctx, user.NewHumanInitializedCheckFailedEvent(ctx, userAgg))
|
_, err = c.eventstore.Push(ctx, user.NewHumanInitializedCheckFailedEvent(ctx, userAgg))
|
||||||
logging.WithFields("userID", userAgg.ID).OnError(err).Error("NewHumanInitializedCheckFailedEvent push failed")
|
logging.WithFields("userID", userAgg.ID).OnError(err).Error("NewHumanInitializedCheckFailedEvent push failed")
|
||||||
|
@ -292,7 +292,7 @@ func TestCommandSide_ResendInitialMail(t *testing.T) {
|
|||||||
func TestCommandSide_VerifyInitCode(t *testing.T) {
|
func TestCommandSide_VerifyInitCode(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
@ -455,7 +455,7 @@ func (c *Commands) sendHumanOTP(
|
|||||||
if !existingOTP.OTPAdded() {
|
if !existingOTP.OTPAdded() {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-SFD52", "Errors.User.MFA.OTP.NotReady")
|
||||||
}
|
}
|
||||||
config, err := secretGeneratorConfigWithDefault(ctx, c.eventstore.Filter, secretGeneratorType, defaultSecretGenerator)
|
config, err := cryptoGeneratorConfigWithDefault(ctx, c.eventstore.Filter, secretGeneratorType, defaultSecretGenerator) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -515,7 +515,7 @@ func (c *Commands) humanCheckOTP(
|
|||||||
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound")
|
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-S34gh", "Errors.User.Code.NotFound")
|
||||||
}
|
}
|
||||||
userAgg := &user.NewAggregate(userID, existingOTP.ResourceOwner()).Aggregate
|
userAgg := &user.NewAggregate(userID, existingOTP.ResourceOwner()).Aggregate
|
||||||
err = crypto.VerifyCodeWithAlgorithm(existingOTP.CodeCreationDate(), existingOTP.CodeExpiry(), existingOTP.Code(), code, c.userEncryption)
|
err = crypto.VerifyCode(existingOTP.CodeCreationDate(), existingOTP.CodeExpiry(), existingOTP.Code(), code, c.userEncryption)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, err = c.eventstore.Push(ctx, checkSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
|
_, err = c.eventstore.Push(ctx, checkSucceededEvent(ctx, userAgg, authRequestDomainToAuthRequestInfo(authRequest)))
|
||||||
return err
|
return err
|
||||||
|
@ -53,7 +53,7 @@ func (c *Commands) SetPasswordWithVerifyCode(ctx context.Context, orgID, userID,
|
|||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.Code.NotFound")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M9fs", "Errors.User.Code.NotFound")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = crypto.VerifyCodeWithAlgorithm(wm.CodeCreationDate, wm.CodeExpiry, wm.Code, code, c.userEncryption)
|
err = crypto.VerifyCode(wm.CodeCreationDate, wm.CodeExpiry, wm.Code, code, c.userEncryption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,11 @@ func (wm *HumanPasswordWriteModel) Reduce() error {
|
|||||||
for _, event := range wm.Events {
|
for _, event := range wm.Events {
|
||||||
switch e := event.(type) {
|
switch e := event.(type) {
|
||||||
case *user.HumanAddedEvent:
|
case *user.HumanAddedEvent:
|
||||||
wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.EncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.SecretChangeRequired = e.ChangeRequired
|
wm.SecretChangeRequired = e.ChangeRequired
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
case *user.HumanRegisteredEvent:
|
case *user.HumanRegisteredEvent:
|
||||||
wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.EncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.SecretChangeRequired = e.ChangeRequired
|
wm.SecretChangeRequired = e.ChangeRequired
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
case *user.HumanInitialCodeAddedEvent:
|
case *user.HumanInitialCodeAddedEvent:
|
||||||
@ -48,7 +48,7 @@ func (wm *HumanPasswordWriteModel) Reduce() error {
|
|||||||
case *user.HumanInitializedCheckSucceededEvent:
|
case *user.HumanInitializedCheckSucceededEvent:
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
case *user.HumanPasswordChangedEvent:
|
case *user.HumanPasswordChangedEvent:
|
||||||
wm.EncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.EncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.SecretChangeRequired = e.ChangeRequired
|
wm.SecretChangeRequired = e.ChangeRequired
|
||||||
wm.Code = nil
|
wm.Code = nil
|
||||||
wm.PasswordCheckFailedCount = 0
|
wm.PasswordCheckFailedCount = 0
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
func TestCommandSide_SetOneTimePassword(t *testing.T) {
|
func TestCommandSide_SetOneTimePassword(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
@ -270,7 +270,7 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
userEncryption crypto.EncryptionAlgorithm
|
userEncryption crypto.EncryptionAlgorithm
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -598,7 +598,7 @@ func TestCommandSide_SetPasswordWithVerifyCode(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommandSide_ChangePassword(t *testing.T) {
|
func TestCommandSide_ChangePassword(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -1202,7 +1202,7 @@ func TestCommandSide_PasswordCodeSent(t *testing.T) {
|
|||||||
func TestCommandSide_CheckPassword(t *testing.T) {
|
func TestCommandSide_CheckPassword(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
@ -79,7 +79,7 @@ func (c *Commands) VerifyHumanPhone(ctx context.Context, userID, code, resourceo
|
|||||||
}
|
}
|
||||||
|
|
||||||
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&existingCode.WriteModel)
|
||||||
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, phoneCodeGenerator)
|
err = crypto.VerifyCode(existingCode.CodeCreationDate, existingCode.CodeExpiry, existingCode.Code, code, phoneCodeGenerator.Alg())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
|
pushedEvents, err := c.eventstore.Push(ctx, user.NewHumanPhoneVerifiedEvent(ctx, userAgg))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +115,7 @@ func (c *Commands) CreateHumanPhoneVerificationCode(ctx context.Context, userID,
|
|||||||
if existingPhone.IsPhoneVerified {
|
if existingPhone.IsPhoneVerified {
|
||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M9sf", "Errors.User.Phone.AlreadyVerified")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2M9sf", "Errors.User.Phone.AlreadyVerified")
|
||||||
}
|
}
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode)
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
codeAlg crypto.EncryptionAlgorithm
|
codeAlg crypto.EncryptionAlgorithm
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -245,7 +245,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -312,7 +312,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -380,7 +380,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -450,7 +450,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -521,7 +521,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -593,7 +593,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -996,7 +996,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("phonecode", time.Hour),
|
newCode: mockEncryptedCode("phonecode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1061,7 +1061,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1136,7 +1136,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("phoneCode", time.Hour),
|
newCode: mockEncryptedCode("phoneCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1204,7 +1204,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
codeAlg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1242,7 +1242,7 @@ func TestCommandSide_AddHuman(t *testing.T) {
|
|||||||
userPasswordHasher: tt.fields.userPasswordHasher,
|
userPasswordHasher: tt.fields.userPasswordHasher,
|
||||||
userEncryption: tt.fields.codeAlg,
|
userEncryption: tt.fields.codeAlg,
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
}
|
}
|
||||||
err := r.AddHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.allowInitMail)
|
err := r.AddHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.allowInitMail)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
@ -1266,7 +1266,7 @@ func TestCommandSide_ImportHuman(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -2483,7 +2483,7 @@ func TestCommandSide_RegisterHuman(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -4328,7 +4328,7 @@ func TestAddHumanCommand(t *testing.T) {
|
|||||||
type args struct {
|
type args struct {
|
||||||
human *AddHuman
|
human *AddHuman
|
||||||
orgID string
|
orgID string
|
||||||
hasher *crypto.PasswordHasher
|
hasher *crypto.Hasher
|
||||||
filter preparation.FilterToQueryReducer
|
filter preparation.FilterToQueryReducer
|
||||||
codeAlg crypto.EncryptionAlgorithm
|
codeAlg crypto.EncryptionAlgorithm
|
||||||
allowInitMail bool
|
allowInitMail bool
|
||||||
|
@ -575,7 +575,7 @@ func (c *Commands) humanVerifyPasswordlessInitCode(ctx context.Context, userID,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = crypto.VerifyCode(initCode.ChangeDate, initCode.Expiration, initCode.CryptoCode, verificationCode, passwordlessCodeGenerator)
|
err = crypto.VerifyCode(initCode.ChangeDate, initCode.Expiration, initCode.CryptoCode, verificationCode, passwordlessCodeGenerator.Alg())
|
||||||
if err != nil || initCode.State != domain.PasswordlessInitCodeStateActive {
|
if err != nil || initCode.State != domain.PasswordlessInitCodeStateActive {
|
||||||
userAgg := UserAggregateFromWriteModel(&initCode.WriteModel)
|
userAgg := UserAggregateFromWriteModel(&initCode.WriteModel)
|
||||||
_, err = c.eventstore.Push(ctx, usr_repo.NewHumanPasswordlessInitCodeCheckFailedEvent(ctx, userAgg, codeID))
|
_, err = c.eventstore.Push(ctx, usr_repo.NewHumanPasswordlessInitCodeCheckFailedEvent(ctx, userAgg, codeID))
|
||||||
|
@ -18,8 +18,7 @@ type MachineWriteModel struct {
|
|||||||
Description string
|
Description string
|
||||||
UserState domain.UserState
|
UserState domain.UserState
|
||||||
AccessTokenType domain.OIDCTokenType
|
AccessTokenType domain.OIDCTokenType
|
||||||
|
HashedSecret string
|
||||||
ClientSecret *crypto.CryptoValue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMachineWriteModel(userID, resourceOwner string) *MachineWriteModel {
|
func NewMachineWriteModel(userID, resourceOwner string) *MachineWriteModel {
|
||||||
@ -71,9 +70,11 @@ func (wm *MachineWriteModel) Reduce() error {
|
|||||||
case *user.UserRemovedEvent:
|
case *user.UserRemovedEvent:
|
||||||
wm.UserState = domain.UserStateDeleted
|
wm.UserState = domain.UserStateDeleted
|
||||||
case *user.MachineSecretSetEvent:
|
case *user.MachineSecretSetEvent:
|
||||||
wm.ClientSecret = e.ClientSecret
|
wm.HashedSecret = crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)
|
||||||
case *user.MachineSecretRemovedEvent:
|
case *user.MachineSecretRemovedEvent:
|
||||||
wm.ClientSecret = nil
|
wm.HashedSecret = ""
|
||||||
|
case *user.MachineSecretHashUpdatedEvent:
|
||||||
|
wm.HashedSecret = e.HashedSecret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wm.WriteModel.Reduce()
|
return wm.WriteModel.Reduce()
|
||||||
@ -94,8 +95,9 @@ func (wm *MachineWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
user.UserReactivatedType,
|
user.UserReactivatedType,
|
||||||
user.UserRemovedType,
|
user.UserRemovedType,
|
||||||
user.MachineSecretSetType,
|
user.MachineSecretSetType,
|
||||||
user.MachineSecretRemovedType).
|
user.MachineSecretRemovedType,
|
||||||
Builder()
|
user.MachineSecretHashUpdatedType,
|
||||||
|
).Builder()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wm *MachineWriteModel) NewChangedEvent(
|
func (wm *MachineWriteModel) NewChangedEvent(
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
"github.com/zitadel/zitadel/internal/repository/user"
|
||||||
@ -15,9 +14,9 @@ type GenerateMachineSecret struct {
|
|||||||
ClientSecret string
|
ClientSecret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) GenerateMachineSecret(ctx context.Context, userID string, resourceOwner string, generator crypto.Generator, set *GenerateMachineSecret) (*domain.ObjectDetails, error) {
|
func (c *Commands) GenerateMachineSecret(ctx context.Context, userID string, resourceOwner string, set *GenerateMachineSecret) (*domain.ObjectDetails, error) {
|
||||||
agg := user.NewAggregate(userID, resourceOwner)
|
agg := user.NewAggregate(userID, resourceOwner)
|
||||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, prepareGenerateMachineSecret(agg, generator, set))
|
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareGenerateMachineSecret(agg, set)) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -34,7 +33,7 @@ func (c *Commands) GenerateMachineSecret(ctx context.Context, userID string, res
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareGenerateMachineSecret(a *user.Aggregate, generator crypto.Generator, set *GenerateMachineSecret) preparation.Validation {
|
func (c *Commands) prepareGenerateMachineSecret(a *user.Aggregate, set *GenerateMachineSecret) preparation.Validation {
|
||||||
return func() (_ preparation.CreateCommands, err error) {
|
return func() (_ preparation.CreateCommands, err error) {
|
||||||
if a.ResourceOwner == "" {
|
if a.ResourceOwner == "" {
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-x0992n", "Errors.ResourceOwnerMissing")
|
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-x0992n", "Errors.ResourceOwnerMissing")
|
||||||
@ -50,15 +49,14 @@ func prepareGenerateMachineSecret(a *user.Aggregate, generator crypto.Generator,
|
|||||||
if !isUserStateExists(writeModel.UserState) {
|
if !isUserStateExists(writeModel.UserState) {
|
||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-x8910n", "Errors.User.NotExisting")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-x8910n", "Errors.User.NotExisting")
|
||||||
}
|
}
|
||||||
|
encodedHash, plain, err := c.newHashedSecret(ctx, filter)
|
||||||
clientSecret, secretString, err := domain.NewMachineClientSecret(generator)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
set.ClientSecret = secretString
|
set.ClientSecret = plain
|
||||||
|
|
||||||
return []eventstore.Command{
|
return []eventstore.Command{
|
||||||
user.NewMachineSecretSetEvent(ctx, &a.Aggregate, clientSecret),
|
user.NewMachineSecretSetEvent(ctx, &a.Aggregate, encodedHash),
|
||||||
}, nil
|
}, nil
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -99,7 +97,7 @@ func prepareRemoveMachineSecret(a *user.Aggregate) preparation.Validation {
|
|||||||
if !isUserStateExists(writeModel.UserState) {
|
if !isUserStateExists(writeModel.UserState) {
|
||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-x7s802", "Errors.User.NotExisting")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-x7s802", "Errors.User.NotExisting")
|
||||||
}
|
}
|
||||||
if writeModel.ClientSecret == nil {
|
if writeModel.HashedSecret == "" {
|
||||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-coi82n", "Errors.User.Machine.Secret.NotExisting")
|
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-coi82n", "Errors.User.Machine.Secret.NotExisting")
|
||||||
}
|
}
|
||||||
return []eventstore.Command{
|
return []eventstore.Command{
|
||||||
@ -109,9 +107,16 @@ func prepareRemoveMachineSecret(a *user.Aggregate) preparation.Validation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) MachineSecretCheckSucceeded(ctx context.Context, userID, resourceOwner string) {
|
func (c *Commands) MachineSecretCheckSucceeded(ctx context.Context, userID, resourceOwner, updated string) {
|
||||||
agg := user.NewAggregate(userID, resourceOwner)
|
agg := user.NewAggregate(userID, resourceOwner)
|
||||||
c.asyncPush(ctx, user.NewMachineSecretCheckSucceededEvent(ctx, &agg.Aggregate))
|
cmds := append(
|
||||||
|
make([]eventstore.Command, 0, 2),
|
||||||
|
user.NewMachineSecretCheckSucceededEvent(ctx, &agg.Aggregate),
|
||||||
|
)
|
||||||
|
if updated != "" {
|
||||||
|
cmds = append(cmds, user.NewMachineSecretHashUpdatedEvent(ctx, &agg.Aggregate, updated))
|
||||||
|
}
|
||||||
|
c.asyncPush(ctx, cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) MachineSecretCheckFailed(ctx context.Context, userID, resourceOwner string) {
|
func (c *Commands) MachineSecretCheckFailed(ctx context.Context, userID, resourceOwner string) {
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
"github.com/zitadel/zitadel/internal/repository/user"
|
||||||
@ -17,13 +16,12 @@ import (
|
|||||||
|
|
||||||
func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore func(*testing.T) *eventstore.Eventstore
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
userID string
|
userID string
|
||||||
resourceOwner string
|
resourceOwner string
|
||||||
generator crypto.Generator
|
|
||||||
set *GenerateMachineSecret
|
set *GenerateMachineSecret
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
@ -40,15 +38,12 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "user invalid, invalid argument error userID",
|
name: "user invalid, invalid argument error userID",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "",
|
userID: "",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
generator: GetMockSecretGenerator(t),
|
|
||||||
set: nil,
|
set: nil,
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -58,15 +53,12 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "user invalid, invalid argument error resourceowner",
|
name: "user invalid, invalid argument error resourceowner",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(),
|
||||||
t,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "",
|
resourceOwner: "",
|
||||||
generator: GetMockSecretGenerator(t),
|
|
||||||
set: nil,
|
set: nil,
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -76,8 +68,7 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "user not existing, precondition error",
|
name: "user not existing, precondition error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -85,7 +76,6 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
generator: GetMockSecretGenerator(t),
|
|
||||||
set: nil,
|
set: nil,
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -95,8 +85,7 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "add machine secret, ok",
|
name: "add machine secret, ok",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
eventstore: eventstoreExpect(
|
eventstore: expectEventstore(
|
||||||
t,
|
|
||||||
expectFilter(
|
expectFilter(
|
||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewMachineAddedEvent(context.Background(),
|
user.NewMachineAddedEvent(context.Background(),
|
||||||
@ -112,12 +101,7 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
expectPush(
|
expectPush(
|
||||||
user.NewMachineSecretSetEvent(context.Background(),
|
user.NewMachineSecretSetEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -126,7 +110,6 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
userID: "user1",
|
userID: "user1",
|
||||||
resourceOwner: "org1",
|
resourceOwner: "org1",
|
||||||
generator: GetMockSecretGenerator(t),
|
|
||||||
set: &GenerateMachineSecret{},
|
set: &GenerateMachineSecret{},
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
@ -134,7 +117,7 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
ResourceOwner: "org1",
|
ResourceOwner: "org1",
|
||||||
},
|
},
|
||||||
secret: &GenerateMachineSecret{
|
secret: &GenerateMachineSecret{
|
||||||
ClientSecret: "a",
|
ClientSecret: "secret",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -142,9 +125,13 @@ func TestCommandSide_GenerateMachineSecret(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore(t),
|
||||||
|
newHashedSecret: mockHashedSecret("secret"),
|
||||||
|
defaultSecretGenerators: &SecretGenerators{
|
||||||
|
ClientSecret: emptyConfig,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
got, err := r.GenerateMachineSecret(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.generator, tt.args.set)
|
got, err := r.GenerateMachineSecret(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.set)
|
||||||
if tt.res.err == nil {
|
if tt.res.err == nil {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -274,12 +261,7 @@ func TestCommandSide_RemoveMachineSecret(t *testing.T) {
|
|||||||
eventFromEventPusher(
|
eventFromEventPusher(
|
||||||
user.NewMachineSecretSetEvent(context.Background(),
|
user.NewMachineSecretSetEvent(context.Background(),
|
||||||
&user.NewAggregate("user1", "org1").Aggregate,
|
&user.NewAggregate("user1", "org1").Aggregate,
|
||||||
&crypto.CryptoValue{
|
"secret",
|
||||||
CryptoType: crypto.TypeEncryption,
|
|
||||||
Algorithm: "enc",
|
|
||||||
KeyID: "id",
|
|
||||||
Crypted: []byte("a"),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -333,7 +315,7 @@ func TestCommands_MachineSecretCheckSucceeded(t *testing.T) {
|
|||||||
expectPushSlow(time.Second/100, cmd),
|
expectPushSlow(time.Second/100, cmd),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
c.MachineSecretCheckSucceeded(ctx, "userID", "orgID")
|
c.MachineSecretCheckSucceeded(ctx, "userID", "orgID", "")
|
||||||
require.NoError(t, c.Close(ctx))
|
require.NoError(t, c.Close(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func (c *Commands) ChangeUserEmailVerified(ctx context.Context, userID, email st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) changeUserEmailWithCode(ctx context.Context, userID, email string, alg crypto.EncryptionAlgorithm, returnCode bool, urlTmpl string) (*domain.Email, error) {
|
func (c *Commands) changeUserEmailWithCode(ctx context.Context, userID, email string, alg crypto.EncryptionAlgorithm, returnCode bool, urlTmpl string) (*domain.Email, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode)
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ func (c *Commands) changeUserEmailWithCode(ctx context.Context, userID, email st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) resendUserEmailCode(ctx context.Context, userID string, alg crypto.EncryptionAlgorithm, returnCode bool, urlTmpl string) (*domain.Email, error) {
|
func (c *Commands) resendUserEmailCode(ctx context.Context, userID string, alg crypto.EncryptionAlgorithm, returnCode bool, urlTmpl string) (*domain.Email, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode) //nolint:staticcheck
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ func (c *Commands) resendUserEmailCodeWithGeneratorEvents(ctx context.Context, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) VerifyUserEmail(ctx context.Context, userID, code string, alg crypto.EncryptionAlgorithm) (*domain.ObjectDetails, error) {
|
func (c *Commands) VerifyUserEmail(ctx context.Context, userID, code string, alg crypto.EncryptionAlgorithm) (*domain.ObjectDetails, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode)
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyEmailCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ func (c *UserEmailEvents) VerifyCode(ctx context.Context, code string, gen crypt
|
|||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Fia4a", "Errors.User.Code.Empty")
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Fia4a", "Errors.User.Code.Empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := crypto.VerifyCode(c.model.CodeCreationDate, c.model.CodeExpiry, c.model.Code, code, gen)
|
err := crypto.VerifyCode(c.model.CodeCreationDate, c.model.CodeExpiry, c.model.Code, code, gen.Alg())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.events = append(c.events, user.NewHumanEmailVerifiedEvent(ctx, c.aggregate))
|
c.events = append(c.events, user.NewHumanEmailVerifiedEvent(ctx, c.aggregate))
|
||||||
return nil
|
return nil
|
||||||
|
@ -51,7 +51,7 @@ type Password struct {
|
|||||||
ChangeRequired bool
|
ChangeRequired bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *ChangeHuman) Validate(hasher *crypto.PasswordHasher) (err error) {
|
func (h *ChangeHuman) Validate(hasher *crypto.Hasher) (err error) {
|
||||||
if h.Email != nil && h.Email.Address != "" {
|
if h.Email != nil && h.Email.Address != "" {
|
||||||
if err := h.Email.Validate(); err != nil {
|
if err := h.Email.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -72,7 +72,7 @@ func (h *ChangeHuman) Validate(hasher *crypto.PasswordHasher) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Password) Validate(hasher *crypto.PasswordHasher) error {
|
func (p *Password) Validate(hasher *crypto.Hasher) error {
|
||||||
if p.EncodedPasswordHash != nil {
|
if p.EncodedPasswordHash != nil {
|
||||||
if !hasher.EncodingSupported(*p.EncodedPasswordHash) {
|
if !hasher.EncodingSupported(*p.EncodedPasswordHash) {
|
||||||
return zerrors.ThrowInvalidArgument(nil, "USER-oz74onzvqr", "Errors.User.Password.NotSupported")
|
return zerrors.ThrowInvalidArgument(nil, "USER-oz74onzvqr", "Errors.User.Password.NotSupported")
|
||||||
@ -373,7 +373,7 @@ func (c *Commands) changeUserPassword(ctx context.Context, cmds []eventstore.Com
|
|||||||
|
|
||||||
// Either have a code to set the password
|
// Either have a code to set the password
|
||||||
if password.PasswordCode != nil {
|
if password.PasswordCode != nil {
|
||||||
if err := crypto.VerifyCodeWithAlgorithm(wm.PasswordCodeCreationDate, wm.PasswordCodeExpiry, wm.PasswordCode, *password.PasswordCode, alg); err != nil {
|
if err := crypto.VerifyCode(wm.PasswordCodeCreationDate, wm.PasswordCodeExpiry, wm.PasswordCode, *password.PasswordCode, alg); err != nil {
|
||||||
return cmds, err
|
return cmds, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,8 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
@ -247,7 +247,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -283,7 +283,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -349,7 +349,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -420,7 +420,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -492,7 +492,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -565,7 +565,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -974,7 +974,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
newCode: mockCode("phonecode", time.Hour),
|
newCode: mockEncryptedCode("phonecode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1040,7 +1040,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1116,7 +1116,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
userPasswordHasher: mockPasswordHasher("x"),
|
userPasswordHasher: mockPasswordHasher("x"),
|
||||||
newCode: mockCode("phoneCode", time.Hour),
|
newCode: mockEncryptedCode("phoneCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1185,7 +1185,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "user1"),
|
||||||
newCode: mockCode("userinit", time.Hour),
|
newCode: mockEncryptedCode("userinit", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1223,7 +1223,7 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
eventstore: tt.fields.eventstore(t),
|
eventstore: tt.fields.eventstore(t),
|
||||||
userPasswordHasher: tt.fields.userPasswordHasher,
|
userPasswordHasher: tt.fields.userPasswordHasher,
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
checkPermission: tt.fields.checkPermission,
|
checkPermission: tt.fields.checkPermission,
|
||||||
}
|
}
|
||||||
err := r.AddUserHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.allowInitMail, tt.args.codeAlg)
|
err := r.AddUserHuman(tt.args.ctx, tt.args.orgID, tt.args.human, tt.args.allowInitMail, tt.args.codeAlg)
|
||||||
@ -1247,8 +1247,8 @@ func TestCommandSide_AddUserHuman(t *testing.T) {
|
|||||||
func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
userPasswordHasher *crypto.PasswordHasher
|
userPasswordHasher *crypto.Hasher
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
@ -1562,7 +1562,7 @@ func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1741,7 +1741,7 @@ func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("emailCode", time.Hour),
|
newCode: mockEncryptedCode("emailCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1791,7 +1791,7 @@ func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("phoneCode", time.Hour),
|
newCode: mockEncryptedCode("phoneCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -1939,7 +1939,7 @@ func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("phoneCode", time.Hour),
|
newCode: mockEncryptedCode("phoneCode", time.Hour),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -2546,7 +2546,7 @@ func TestCommandSide_ChangeUserHuman(t *testing.T) {
|
|||||||
r := &Commands{
|
r := &Commands{
|
||||||
eventstore: tt.fields.eventstore(t),
|
eventstore: tt.fields.eventstore(t),
|
||||||
userPasswordHasher: tt.fields.userPasswordHasher,
|
userPasswordHasher: tt.fields.userPasswordHasher,
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
checkPermission: tt.fields.checkPermission,
|
checkPermission: tt.fields.checkPermission,
|
||||||
}
|
}
|
||||||
err := r.ChangeUserHuman(tt.args.ctx, tt.args.human, tt.args.codeAlg)
|
err := r.ChangeUserHuman(tt.args.ctx, tt.args.human, tt.args.codeAlg)
|
||||||
|
@ -266,7 +266,7 @@ func (wm *UserV2WriteModel) Reduce() error {
|
|||||||
case *user.HumanPasswordCheckSucceededEvent:
|
case *user.HumanPasswordCheckSucceededEvent:
|
||||||
wm.PasswordCheckFailedCount = 0
|
wm.PasswordCheckFailedCount = 0
|
||||||
case *user.HumanPasswordChangedEvent:
|
case *user.HumanPasswordChangedEvent:
|
||||||
wm.PasswordEncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.PasswordEncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.PasswordChangeRequired = e.ChangeRequired
|
wm.PasswordChangeRequired = e.ChangeRequired
|
||||||
wm.EmptyPasswordCode()
|
wm.EmptyPasswordCode()
|
||||||
case *user.HumanPasswordCodeAddedEvent:
|
case *user.HumanPasswordCodeAddedEvent:
|
||||||
@ -470,7 +470,7 @@ func (wm *UserV2WriteModel) reduceHumanAddedEvent(e *user.HumanAddedEvent) {
|
|||||||
wm.Email = e.EmailAddress
|
wm.Email = e.EmailAddress
|
||||||
wm.Phone = e.PhoneNumber
|
wm.Phone = e.PhoneNumber
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
wm.PasswordEncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.PasswordEncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.PasswordChangeRequired = e.ChangeRequired
|
wm.PasswordChangeRequired = e.ChangeRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ func (wm *UserV2WriteModel) reduceHumanRegisteredEvent(e *user.HumanRegisteredEv
|
|||||||
wm.Email = e.EmailAddress
|
wm.Email = e.EmailAddress
|
||||||
wm.Phone = e.PhoneNumber
|
wm.Phone = e.PhoneNumber
|
||||||
wm.UserState = domain.UserStateActive
|
wm.UserState = domain.UserStateActive
|
||||||
wm.PasswordEncodedHash = user.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
wm.PasswordEncodedHash = crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash)
|
||||||
wm.PasswordChangeRequired = e.ChangeRequired
|
wm.PasswordChangeRequired = e.ChangeRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ func (c *Commands) verifyUserPasskeyCode(ctx context.Context, userID, resourceOw
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = verifyCryptoCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg, wm.ChangeDate, wm.Expiration, wm.CryptoCode, code)
|
err = verifyEncryptedCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg, wm.ChangeDate, wm.Expiration, wm.CryptoCode, code) //nolint:staticcheck
|
||||||
if err != nil || wm.State != domain.PasswordlessInitCodeStateActive {
|
if err != nil || wm.State != domain.PasswordlessInitCodeStateActive {
|
||||||
c.verifyUserPasskeyCodeFailed(ctx, wm)
|
c.verifyUserPasskeyCodeFailed(ctx, wm)
|
||||||
return nil, zerrors.ThrowInvalidArgument(err, "COMMAND-Eeb2a", "Errors.User.Code.Invalid")
|
return nil, zerrors.ThrowInvalidArgument(err, "COMMAND-Eeb2a", "Errors.User.Code.Invalid")
|
||||||
@ -156,6 +156,6 @@ func (c *Commands) addUserPasskeyCode(ctx context.Context, userID, resourceOwner
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) newPasskeyCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*CryptoCode, error) {
|
func (c *Commands) newPasskeyCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (*EncryptedCode, error) {
|
||||||
return c.newCode(ctx, filter, domain.SecretGeneratorTypePasswordlessInitCode, alg)
|
return c.newEncryptedCode(ctx, filter, domain.SecretGeneratorTypePasswordlessInitCode, alg)
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ func TestCommands_RegisterUserPasskeyWithCode(t *testing.T) {
|
|||||||
es := eventstoreExpect(t,
|
es := eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
||||||
)
|
)
|
||||||
code, err := newCryptoCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg)
|
code, err := newEncryptedCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) //nolint:staticcheck
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
type fields struct {
|
type fields struct {
|
||||||
@ -236,7 +236,7 @@ func TestCommands_verifyUserPasskeyCode(t *testing.T) {
|
|||||||
es := eventstoreExpect(t,
|
es := eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
||||||
)
|
)
|
||||||
code, err := newCryptoCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg)
|
code, err := newEncryptedCode(ctx, es.Filter, domain.SecretGeneratorTypePasswordlessInitCode, alg) //nolint:staticcheck
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
|
|
||||||
@ -457,7 +457,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) {
|
|||||||
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
type fields struct {
|
type fields struct {
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
@ -475,7 +475,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "id generator error",
|
name: "id generator error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Hour),
|
newCode: mockEncryptedCode("passkey1", time.Hour),
|
||||||
eventstore: expectEventstore(),
|
eventstore: expectEventstore(),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
||||||
},
|
},
|
||||||
@ -488,7 +488,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Minute),
|
newCode: mockEncryptedCode("passkey1", time.Minute),
|
||||||
eventstore: expectEventstore(
|
eventstore: expectEventstore(
|
||||||
expectFilter(eventFromEventPusher(
|
expectFilter(eventFromEventPusher(
|
||||||
user.NewHumanAddedEvent(context.Background(),
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
@ -530,7 +530,7 @@ func TestCommands_AddUserPasskeyCode(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := &Commands{
|
c := &Commands{
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
eventstore: tt.fields.eventstore(t),
|
eventstore: tt.fields.eventstore(t),
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
}
|
}
|
||||||
@ -546,7 +546,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) {
|
|||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
|
|
||||||
type fields struct {
|
type fields struct {
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
@ -565,7 +565,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "template error",
|
name: "template error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t),
|
eventstore: eventstoreExpect(t),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
@ -578,7 +578,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "id generator error",
|
name: "id generator error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t),
|
eventstore: eventstoreExpect(t),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
||||||
},
|
},
|
||||||
@ -592,7 +592,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Minute),
|
newCode: mockEncryptedCode("passkey1", time.Minute),
|
||||||
eventstore: eventstoreExpect(t,
|
eventstore: eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(
|
expectFilter(eventFromEventPusher(
|
||||||
user.NewHumanAddedEvent(context.Background(),
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
@ -638,7 +638,7 @@ func TestCommands_AddUserPasskeyCodeURLTemplate(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := &Commands{
|
c := &Commands{
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
}
|
}
|
||||||
@ -653,7 +653,7 @@ func TestCommands_AddUserPasskeyCodeReturn(t *testing.T) {
|
|||||||
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
type fields struct {
|
type fields struct {
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
@ -671,7 +671,7 @@ func TestCommands_AddUserPasskeyCodeReturn(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "id generator error",
|
name: "id generator error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t),
|
eventstore: eventstoreExpect(t),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
||||||
},
|
},
|
||||||
@ -684,7 +684,7 @@ func TestCommands_AddUserPasskeyCodeReturn(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Minute),
|
newCode: mockEncryptedCode("passkey1", time.Minute),
|
||||||
eventstore: eventstoreExpect(t,
|
eventstore: eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(
|
expectFilter(eventFromEventPusher(
|
||||||
user.NewHumanAddedEvent(context.Background(),
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
@ -730,7 +730,7 @@ func TestCommands_AddUserPasskeyCodeReturn(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := &Commands{
|
c := &Commands{
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
}
|
}
|
||||||
@ -745,7 +745,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
alg := crypto.CreateMockEncryptionAlg(gomock.NewController(t))
|
||||||
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
userAgg := &user.NewAggregate("user1", "org1").Aggregate
|
||||||
type fields struct {
|
type fields struct {
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
idGenerator id.Generator
|
idGenerator id.Generator
|
||||||
}
|
}
|
||||||
@ -763,7 +763,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "id generator error",
|
name: "id generator error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t),
|
eventstore: eventstoreExpect(t),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
idGenerator: id_mock.NewIDGeneratorExpectError(t, io.ErrClosedPipe),
|
||||||
},
|
},
|
||||||
@ -776,7 +776,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "crypto error",
|
name: "crypto error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
eventstore: eventstoreExpect(t, expectFilterError(io.ErrClosedPipe)),
|
||||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "123"),
|
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "123"),
|
||||||
},
|
},
|
||||||
@ -789,7 +789,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "filter query error",
|
name: "filter query error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: newCryptoCode,
|
newCode: newEncryptedCode,
|
||||||
eventstore: eventstoreExpect(t,
|
eventstore: eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
expectFilter(eventFromEventPusher(testSecretGeneratorAddedEvent(domain.SecretGeneratorTypePasswordlessInitCode))),
|
||||||
expectFilterError(io.ErrClosedPipe),
|
expectFilterError(io.ErrClosedPipe),
|
||||||
@ -805,7 +805,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "push error",
|
name: "push error",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Minute),
|
newCode: mockEncryptedCode("passkey1", time.Minute),
|
||||||
eventstore: eventstoreExpect(t,
|
eventstore: eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(
|
expectFilter(eventFromEventPusher(
|
||||||
user.NewHumanAddedEvent(context.Background(),
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
@ -844,7 +844,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "success",
|
name: "success",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
newCode: mockCode("passkey1", time.Minute),
|
newCode: mockEncryptedCode("passkey1", time.Minute),
|
||||||
eventstore: eventstoreExpect(t,
|
eventstore: eventstoreExpect(t,
|
||||||
expectFilter(eventFromEventPusher(
|
expectFilter(eventFromEventPusher(
|
||||||
user.NewHumanAddedEvent(context.Background(),
|
user.NewHumanAddedEvent(context.Background(),
|
||||||
@ -890,7 +890,7 @@ func TestCommands_addUserPasskeyCode(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := &Commands{
|
c := &Commands{
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func (c *Commands) requestPasswordReset(ctx context.Context, userID string, retu
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code, err := c.newCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordResetCode, c.userEncryption)
|
code, err := c.newEncryptedCode(ctx, c.eventstore.Filter, domain.SecretGeneratorTypePasswordResetCode, c.userEncryption) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
@ -330,7 +330,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||||
userEncryption crypto.EncryptionAlgorithm
|
userEncryption crypto.EncryptionAlgorithm
|
||||||
newCode cryptoCodeFunc
|
newCode encrypedCodeFunc
|
||||||
}
|
}
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -452,7 +452,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("code", 10*time.Minute),
|
newCode: mockEncryptedCode("code", 10*time.Minute),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -492,7 +492,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("code", 10*time.Minute),
|
newCode: mockEncryptedCode("code", 10*time.Minute),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -533,7 +533,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("code", 10*time.Minute),
|
newCode: mockEncryptedCode("code", 10*time.Minute),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -575,7 +575,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
checkPermission: newMockPermissionCheckAllowed(),
|
checkPermission: newMockPermissionCheckAllowed(),
|
||||||
newCode: mockCode("code", 10*time.Minute),
|
newCode: mockEncryptedCode("code", 10*time.Minute),
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
@ -596,7 +596,7 @@ func TestCommands_requestPasswordReset(t *testing.T) {
|
|||||||
checkPermission: tt.fields.checkPermission,
|
checkPermission: tt.fields.checkPermission,
|
||||||
eventstore: tt.fields.eventstore(t),
|
eventstore: tt.fields.eventstore(t),
|
||||||
userEncryption: tt.fields.userEncryption,
|
userEncryption: tt.fields.userEncryption,
|
||||||
newCode: tt.fields.newCode,
|
newEncryptedCode: tt.fields.newCode,
|
||||||
}
|
}
|
||||||
got, gotPlainCode, err := c.requestPasswordReset(tt.args.ctx, tt.args.userID, tt.args.returnCode, tt.args.urlTmpl, tt.args.notificationType)
|
got, gotPlainCode, err := c.requestPasswordReset(tt.args.ctx, tt.args.userID, tt.args.returnCode, tt.args.urlTmpl, tt.args.notificationType)
|
||||||
require.ErrorIs(t, err, tt.res.err)
|
require.ErrorIs(t, err, tt.res.err)
|
||||||
|
@ -55,7 +55,7 @@ func (c *Commands) ResendUserPhoneCodeReturnCode(ctx context.Context, userID str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) changeUserPhoneWithCode(ctx context.Context, userID, phone string, alg crypto.EncryptionAlgorithm, returnCode bool) (*domain.Phone, error) {
|
func (c *Commands) changeUserPhoneWithCode(ctx context.Context, userID, phone string, alg crypto.EncryptionAlgorithm, returnCode bool) (*domain.Phone, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode)
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ func (c *Commands) changeUserPhoneWithCode(ctx context.Context, userID, phone st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) resendUserPhoneCode(ctx context.Context, userID string, alg crypto.EncryptionAlgorithm, returnCode bool) (*domain.Phone, error) {
|
func (c *Commands) resendUserPhoneCode(ctx context.Context, userID string, alg crypto.EncryptionAlgorithm, returnCode bool) (*domain.Phone, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) //nolint:staticcheck
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ func (c *Commands) resendUserPhoneCodeWithGenerator(ctx context.Context, userID
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) VerifyUserPhone(ctx context.Context, userID, code string, alg crypto.EncryptionAlgorithm) (*domain.ObjectDetails, error) {
|
func (c *Commands) VerifyUserPhone(ctx context.Context, userID, code string, alg crypto.EncryptionAlgorithm) (*domain.ObjectDetails, error) {
|
||||||
config, err := secretGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode)
|
config, err := cryptoGeneratorConfig(ctx, c.eventstore.Filter, domain.SecretGeneratorTypeVerifyPhoneCode) //nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ func (c *UserPhoneEvents) VerifyCode(ctx context.Context, code string, gen crypt
|
|||||||
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Fia4a", "Errors.User.Code.Empty")
|
return zerrors.ThrowInvalidArgument(nil, "COMMAND-Fia4a", "Errors.User.Code.Empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := crypto.VerifyCode(c.model.CodeCreationDate, c.model.CodeExpiry, c.model.Code, code, gen)
|
err := crypto.VerifyCode(c.model.CodeCreationDate, c.model.CodeExpiry, c.model.Code, code, gen.Alg())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.events = append(c.events, user.NewHumanPhoneVerifiedEvent(ctx, c.aggregate))
|
c.events = append(c.events, user.NewHumanPhoneVerifiedEvent(ctx, c.aggregate))
|
||||||
return nil
|
return nil
|
||||||
|
@ -8,7 +8,8 @@ import (
|
|||||||
|
|
||||||
type SystemDefaults struct {
|
type SystemDefaults struct {
|
||||||
SecretGenerators SecretGenerators
|
SecretGenerators SecretGenerators
|
||||||
PasswordHasher crypto.PasswordHashConfig
|
PasswordHasher crypto.HashConfig
|
||||||
|
SecretHasher crypto.HashConfig
|
||||||
Multifactors MultifactorConfig
|
Multifactors MultifactorConfig
|
||||||
DomainVerification DomainVerification
|
DomainVerification DomainVerification
|
||||||
Notifications Notifications
|
Notifications Notifications
|
||||||
@ -16,7 +17,6 @@ type SystemDefaults struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SecretGenerators struct {
|
type SecretGenerators struct {
|
||||||
PasswordSaltCost int
|
|
||||||
MachineKeySize uint32
|
MachineKeySize uint32
|
||||||
ApplicationKeySize uint32
|
ApplicationKeySize uint32
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ HashAlgorithm = (*BCrypt)(nil)
|
|
||||||
|
|
||||||
type BCrypt struct {
|
|
||||||
cost int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBCrypt(cost int) *BCrypt {
|
|
||||||
return &BCrypt{cost: cost}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BCrypt) Algorithm() string {
|
|
||||||
return "bcrypt"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BCrypt) Hash(value []byte) ([]byte, error) {
|
|
||||||
return bcrypt.GenerateFromPassword(value, b.cost)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BCrypt) CompareHash(hashed, value []byte) error {
|
|
||||||
return bcrypt.CompareHashAndPassword(hashed, value)
|
|
||||||
}
|
|
@ -26,7 +26,7 @@ type GeneratorConfig struct {
|
|||||||
type Generator interface {
|
type Generator interface {
|
||||||
Length() uint
|
Length() uint
|
||||||
Expiry() time.Duration
|
Expiry() time.Duration
|
||||||
Alg() Crypto
|
Alg() EncryptionAlgorithm
|
||||||
Runes() []rune
|
Runes() []rune
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ type encryptionGenerator struct {
|
|||||||
alg EncryptionAlgorithm
|
alg EncryptionAlgorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *encryptionGenerator) Alg() Crypto {
|
func (g *encryptionGenerator) Alg() EncryptionAlgorithm {
|
||||||
return g.alg
|
return g.alg
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,22 +64,30 @@ func NewEncryptionGenerator(config GeneratorConfig, algorithm EncryptionAlgorith
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashGenerator struct {
|
type HashGenerator struct {
|
||||||
generator
|
generator
|
||||||
alg HashAlgorithm
|
hasher *Hasher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *hashGenerator) Alg() Crypto {
|
func NewHashGenerator(config GeneratorConfig, hasher *Hasher) *HashGenerator {
|
||||||
return g.alg
|
return &HashGenerator{
|
||||||
}
|
|
||||||
|
|
||||||
func NewHashGenerator(config GeneratorConfig, algorithm HashAlgorithm) Generator {
|
|
||||||
return &hashGenerator{
|
|
||||||
newGenerator(config),
|
newGenerator(config),
|
||||||
algorithm,
|
hasher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *HashGenerator) NewCode() (encoded, plain string, err error) {
|
||||||
|
plain, err = GenerateRandomString(g.Length(), g.Runes())
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
encoded, err = g.hasher.Hash(plain)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return encoded, plain, nil
|
||||||
|
}
|
||||||
|
|
||||||
func newGenerator(config GeneratorConfig) generator {
|
func newGenerator(config GeneratorConfig) generator {
|
||||||
var runes []rune
|
var runes []rune
|
||||||
if config.IncludeLowerLetters {
|
if config.IncludeLowerLetters {
|
||||||
@ -120,21 +128,11 @@ func IsCodeExpired(creationDate time.Time, expiry time.Duration) bool {
|
|||||||
return creationDate.Add(expiry).Before(time.Now().UTC())
|
return creationDate.Add(expiry).Before(time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyCode(creationDate time.Time, expiry time.Duration, cryptoCode *CryptoValue, verificationCode string, g Generator) error {
|
func VerifyCode(creationDate time.Time, expiry time.Duration, cryptoCode *CryptoValue, verificationCode string, algorithm EncryptionAlgorithm) error {
|
||||||
return VerifyCodeWithAlgorithm(creationDate, expiry, cryptoCode, verificationCode, g.Alg())
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyCodeWithAlgorithm(creationDate time.Time, expiry time.Duration, cryptoCode *CryptoValue, verificationCode string, algorithm Crypto) error {
|
|
||||||
if IsCodeExpired(creationDate, expiry) {
|
if IsCodeExpired(creationDate, expiry) {
|
||||||
return zerrors.ThrowPreconditionFailed(nil, "CODE-QvUQ4P", "Errors.User.Code.Expired")
|
return zerrors.ThrowPreconditionFailed(nil, "CODE-QvUQ4P", "Errors.User.Code.Expired")
|
||||||
}
|
}
|
||||||
switch alg := algorithm.(type) {
|
return verifyEncryptedCode(cryptoCode, verificationCode, algorithm)
|
||||||
case EncryptionAlgorithm:
|
|
||||||
return verifyEncryptedCode(cryptoCode, verificationCode, alg)
|
|
||||||
case HashAlgorithm:
|
|
||||||
return verifyHashedCode(cryptoCode, verificationCode, alg)
|
|
||||||
}
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "CODE-fW2gNa", "Errors.User.Code.GeneratorAlgNotSupported")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateRandomString(length uint, chars []rune) (string, error) {
|
func GenerateRandomString(length uint, chars []rune) (string, error) {
|
||||||
@ -173,10 +171,3 @@ func verifyEncryptedCode(cryptoCode *CryptoValue, verificationCode string, alg E
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyHashedCode(cryptoCode *CryptoValue, verificationCode string, alg HashAlgorithm) error {
|
|
||||||
if cryptoCode == nil {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-2q3r", "cryptoCode must not be nil")
|
|
||||||
}
|
|
||||||
return CompareHash(cryptoCode, []byte(verificationCode), alg)
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
//
|
//
|
||||||
// mockgen -source code.go -destination ./code_mock.go -package crypto
|
// mockgen -source code.go -destination ./code_mock.go -package crypto
|
||||||
//
|
//
|
||||||
|
|
||||||
// Package crypto is a generated GoMock package.
|
// Package crypto is a generated GoMock package.
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
@ -39,10 +40,10 @@ func (m *MockGenerator) EXPECT() *MockGeneratorMockRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Alg mocks base method.
|
// Alg mocks base method.
|
||||||
func (m *MockGenerator) Alg() Crypto {
|
func (m *MockGenerator) Alg() EncryptionAlgorithm {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Alg")
|
ret := m.ctrl.Call(m, "Alg")
|
||||||
ret0, _ := ret[0].(Crypto)
|
ret0, _ := ret[0].(EncryptionAlgorithm)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,32 +60,13 @@ func createMockEncryptionAlgorithm(ctrl *gomock.Controller, encryptFunction func
|
|||||||
return mCrypto
|
return mCrypto
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMockHashAlg(ctrl *gomock.Controller) HashAlgorithm {
|
func createMockCrypto(t *testing.T) EncryptionAlgorithm {
|
||||||
mCrypto := NewMockHashAlgorithm(ctrl)
|
mCrypto := NewMockEncryptionAlgorithm(gomock.NewController(t))
|
||||||
mCrypto.EXPECT().Algorithm().AnyTimes().Return("hash")
|
|
||||||
mCrypto.EXPECT().Hash(gomock.Any()).AnyTimes().DoAndReturn(
|
|
||||||
func(code []byte) ([]byte, error) {
|
|
||||||
return code, nil
|
|
||||||
},
|
|
||||||
)
|
|
||||||
mCrypto.EXPECT().CompareHash(gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
|
|
||||||
func(hashed, comparer []byte) error {
|
|
||||||
if string(hashed) != string(comparer) {
|
|
||||||
return zerrors.ThrowInternal(nil, "id", "invalid")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return mCrypto
|
|
||||||
}
|
|
||||||
|
|
||||||
func createMockCrypto(t *testing.T) Crypto {
|
|
||||||
mCrypto := NewMockCrypto(gomock.NewController(t))
|
|
||||||
mCrypto.EXPECT().Algorithm().AnyTimes().Return("crypto")
|
mCrypto.EXPECT().Algorithm().AnyTimes().Return("crypto")
|
||||||
return mCrypto
|
return mCrypto
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMockGenerator(t *testing.T, crypto Crypto) Generator {
|
func createMockGenerator(t *testing.T, crypto EncryptionAlgorithm) Generator {
|
||||||
mGenerator := NewMockGenerator(gomock.NewController(t))
|
mGenerator := NewMockGenerator(gomock.NewController(t))
|
||||||
mGenerator.EXPECT().Alg().AnyTimes().Return(crypto)
|
mGenerator.EXPECT().Alg().AnyTimes().Return(crypto)
|
||||||
return mGenerator
|
return mGenerator
|
||||||
|
@ -102,25 +102,10 @@ func TestVerifyCode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"hash alg ok",
|
|
||||||
args{
|
|
||||||
creationDate: time.Now(),
|
|
||||||
expiry: 5 * time.Minute,
|
|
||||||
cryptoCode: &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: "hash",
|
|
||||||
Crypted: []byte("code"),
|
|
||||||
},
|
|
||||||
verificationCode: "code",
|
|
||||||
g: createMockGenerator(t, CreateMockHashAlg(gomock.NewController(t))),
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := VerifyCode(tt.args.creationDate, tt.args.expiry, tt.args.cryptoCode, tt.args.verificationCode, tt.args.g); (err != nil) != tt.wantErr {
|
if err := VerifyCode(tt.args.creationDate, tt.args.expiry, tt.args.cryptoCode, tt.args.verificationCode, tt.args.g.Alg()); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("VerifyCode() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("VerifyCode() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -222,85 +207,3 @@ func Test_verifyEncryptedCode(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_verifyHashedCode(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
cryptoCode *CryptoValue
|
|
||||||
verificationCode string
|
|
||||||
alg HashAlgorithm
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
|
|
||||||
{
|
|
||||||
"nil error",
|
|
||||||
args{
|
|
||||||
cryptoCode: nil,
|
|
||||||
verificationCode: "",
|
|
||||||
alg: CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wrong cryptotype error",
|
|
||||||
args{
|
|
||||||
cryptoCode: &CryptoValue{
|
|
||||||
CryptoType: TypeEncryption,
|
|
||||||
Crypted: nil,
|
|
||||||
},
|
|
||||||
verificationCode: "",
|
|
||||||
alg: CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wrong algorithm error",
|
|
||||||
args{
|
|
||||||
cryptoCode: &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: "hash2",
|
|
||||||
Crypted: nil,
|
|
||||||
},
|
|
||||||
verificationCode: "",
|
|
||||||
alg: CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wrong verification code error",
|
|
||||||
args{
|
|
||||||
cryptoCode: &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: "hash",
|
|
||||||
Crypted: []byte("code"),
|
|
||||||
},
|
|
||||||
verificationCode: "wrong",
|
|
||||||
alg: CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"verification code ok",
|
|
||||||
args{
|
|
||||||
cryptoCode: &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: "hash",
|
|
||||||
Crypted: []byte("code"),
|
|
||||||
},
|
|
||||||
verificationCode: "code",
|
|
||||||
alg: CreateMockHashAlg(gomock.NewController(t)),
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if err := verifyHashedCode(tt.args.cryptoCode, tt.args.verificationCode, tt.args.alg); (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("verifyHashedCode() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -13,12 +13,8 @@ const (
|
|||||||
TypeHash // Depcrecated: use [passwap.Swapper] instead
|
TypeHash // Depcrecated: use [passwap.Swapper] instead
|
||||||
)
|
)
|
||||||
|
|
||||||
type Crypto interface {
|
|
||||||
Algorithm() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type EncryptionAlgorithm interface {
|
type EncryptionAlgorithm interface {
|
||||||
Crypto
|
Algorithm() string
|
||||||
EncryptionKeyID() string
|
EncryptionKeyID() string
|
||||||
DecryptionKeyIDs() []string
|
DecryptionKeyIDs() []string
|
||||||
Encrypt(value []byte) ([]byte, error)
|
Encrypt(value []byte) ([]byte, error)
|
||||||
@ -26,13 +22,6 @@ type EncryptionAlgorithm interface {
|
|||||||
DecryptString(hashed []byte, keyID string) (string, error)
|
DecryptString(hashed []byte, keyID string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depcrecated: use [passwap.Swapper] instead
|
|
||||||
type HashAlgorithm interface {
|
|
||||||
Crypto
|
|
||||||
Hash(value []byte) ([]byte, error)
|
|
||||||
CompareHash(hashed, comparer []byte) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type CryptoValue struct {
|
type CryptoValue struct {
|
||||||
CryptoType CryptoType
|
CryptoType CryptoType
|
||||||
Algorithm string
|
Algorithm string
|
||||||
@ -59,14 +48,8 @@ func (c *CryptoValue) Scan(src interface{}) error {
|
|||||||
|
|
||||||
type CryptoType int
|
type CryptoType int
|
||||||
|
|
||||||
func Crypt(value []byte, c Crypto) (*CryptoValue, error) {
|
func Crypt(value []byte, alg EncryptionAlgorithm) (*CryptoValue, error) {
|
||||||
switch alg := c.(type) {
|
|
||||||
case EncryptionAlgorithm:
|
|
||||||
return Encrypt(value, alg)
|
return Encrypt(value, alg)
|
||||||
case HashAlgorithm:
|
|
||||||
return Hash(value, alg)
|
|
||||||
}
|
|
||||||
return nil, zerrors.ThrowInternal(nil, "CRYPT-r4IaHZ", "algorithm not supported")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Encrypt(value []byte, alg EncryptionAlgorithm) (*CryptoValue, error) {
|
func Encrypt(value []byte, alg EncryptionAlgorithm) (*CryptoValue, error) {
|
||||||
@ -108,33 +91,6 @@ func checkEncryptionAlgorithm(value *CryptoValue, alg EncryptionAlgorithm) error
|
|||||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-Kq12vn", "value was encrypted with a different key")
|
return zerrors.ThrowInvalidArgument(nil, "CRYPT-Kq12vn", "value was encrypted with a different key")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Hash(value []byte, alg HashAlgorithm) (*CryptoValue, error) {
|
|
||||||
hashed, err := alg.Hash(value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(err, "CRYPT-rBVaJU", "error hashing value")
|
|
||||||
}
|
|
||||||
return &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: alg.Algorithm(),
|
|
||||||
Crypted: hashed,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CompareHash(value *CryptoValue, comparer []byte, alg HashAlgorithm) error {
|
|
||||||
if value.Algorithm != alg.Algorithm() {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-HF32f", "value was hashed with a different algorithm")
|
|
||||||
}
|
|
||||||
return alg.CompareHash(value.Crypted, comparer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func FillHash(value []byte, alg HashAlgorithm) *CryptoValue {
|
|
||||||
return &CryptoValue{
|
|
||||||
CryptoType: TypeHash,
|
|
||||||
Algorithm: alg.Algorithm(),
|
|
||||||
Crypted: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckToken(alg EncryptionAlgorithm, token string, content string) error {
|
func CheckToken(alg EncryptionAlgorithm, token string, content string) error {
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return zerrors.ThrowPermissionDenied(nil, "CRYPTO-Sfefs", "Errors.Intent.InvalidToken")
|
return zerrors.ThrowPermissionDenied(nil, "CRYPTO-Sfefs", "Errors.Intent.InvalidToken")
|
||||||
@ -152,3 +108,12 @@ func CheckToken(alg EncryptionAlgorithm, token string, content string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecretOrEncodedHash returns the Crypted value from legacy [CryptoValue] if it is not nil.
|
||||||
|
// otherwise it will returns the encoded hash string.
|
||||||
|
func SecretOrEncodedHash(secret *CryptoValue, encoded string) string {
|
||||||
|
if secret != nil {
|
||||||
|
return string(secret.Crypted)
|
||||||
|
}
|
||||||
|
return encoded
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
//
|
//
|
||||||
// mockgen -source crypto.go -destination ./crypto_mock.go -package crypto
|
// mockgen -source crypto.go -destination ./crypto_mock.go -package crypto
|
||||||
//
|
//
|
||||||
|
|
||||||
// Package crypto is a generated GoMock package.
|
// Package crypto is a generated GoMock package.
|
||||||
package crypto
|
package crypto
|
||||||
|
|
||||||
@ -14,43 +15,6 @@ import (
|
|||||||
gomock "go.uber.org/mock/gomock"
|
gomock "go.uber.org/mock/gomock"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockCrypto is a mock of Crypto interface.
|
|
||||||
type MockCrypto struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockCryptoMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockCryptoMockRecorder is the mock recorder for MockCrypto.
|
|
||||||
type MockCryptoMockRecorder struct {
|
|
||||||
mock *MockCrypto
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockCrypto creates a new mock instance.
|
|
||||||
func NewMockCrypto(ctrl *gomock.Controller) *MockCrypto {
|
|
||||||
mock := &MockCrypto{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockCryptoMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockCrypto) EXPECT() *MockCryptoMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm mocks base method.
|
|
||||||
func (m *MockCrypto) Algorithm() string {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Algorithm")
|
|
||||||
ret0, _ := ret[0].(string)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm indicates an expected call of Algorithm.
|
|
||||||
func (mr *MockCryptoMockRecorder) Algorithm() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Algorithm", reflect.TypeOf((*MockCrypto)(nil).Algorithm))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockEncryptionAlgorithm is a mock of EncryptionAlgorithm interface.
|
// MockEncryptionAlgorithm is a mock of EncryptionAlgorithm interface.
|
||||||
type MockEncryptionAlgorithm struct {
|
type MockEncryptionAlgorithm struct {
|
||||||
ctrl *gomock.Controller
|
ctrl *gomock.Controller
|
||||||
@ -160,69 +124,3 @@ func (mr *MockEncryptionAlgorithmMockRecorder) EncryptionKeyID() *gomock.Call {
|
|||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EncryptionKeyID", reflect.TypeOf((*MockEncryptionAlgorithm)(nil).EncryptionKeyID))
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EncryptionKeyID", reflect.TypeOf((*MockEncryptionAlgorithm)(nil).EncryptionKeyID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MockHashAlgorithm is a mock of HashAlgorithm interface.
|
|
||||||
type MockHashAlgorithm struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockHashAlgorithmMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockHashAlgorithmMockRecorder is the mock recorder for MockHashAlgorithm.
|
|
||||||
type MockHashAlgorithmMockRecorder struct {
|
|
||||||
mock *MockHashAlgorithm
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockHashAlgorithm creates a new mock instance.
|
|
||||||
func NewMockHashAlgorithm(ctrl *gomock.Controller) *MockHashAlgorithm {
|
|
||||||
mock := &MockHashAlgorithm{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockHashAlgorithmMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockHashAlgorithm) EXPECT() *MockHashAlgorithmMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm mocks base method.
|
|
||||||
func (m *MockHashAlgorithm) Algorithm() string {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Algorithm")
|
|
||||||
ret0, _ := ret[0].(string)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Algorithm indicates an expected call of Algorithm.
|
|
||||||
func (mr *MockHashAlgorithmMockRecorder) Algorithm() *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Algorithm", reflect.TypeOf((*MockHashAlgorithm)(nil).Algorithm))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompareHash mocks base method.
|
|
||||||
func (m *MockHashAlgorithm) CompareHash(hashed, comparer []byte) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "CompareHash", hashed, comparer)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompareHash indicates an expected call of CompareHash.
|
|
||||||
func (mr *MockHashAlgorithmMockRecorder) CompareHash(hashed, comparer any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CompareHash", reflect.TypeOf((*MockHashAlgorithm)(nil).CompareHash), hashed, comparer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash mocks base method.
|
|
||||||
func (m *MockHashAlgorithm) Hash(value []byte) ([]byte, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Hash", value)
|
|
||||||
ret0, _ := ret[0].([]byte)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash indicates an expected call of Hash.
|
|
||||||
func (mr *MockHashAlgorithmMockRecorder) Hash(value any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hash", reflect.TypeOf((*MockHashAlgorithm)(nil).Hash), value)
|
|
||||||
}
|
|
||||||
|
@ -60,7 +60,7 @@ func (a *alg) Algorithm() string {
|
|||||||
func TestCrypt(t *testing.T) {
|
func TestCrypt(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
value []byte
|
value []byte
|
||||||
c Crypto
|
c EncryptionAlgorithm
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -74,18 +74,6 @@ func TestCrypt(t *testing.T) {
|
|||||||
&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"hash",
|
|
||||||
args{[]byte("test"), &mockHashCrypto{}},
|
|
||||||
&CryptoValue{CryptoType: TypeHash, Algorithm: "hash", Crypted: []byte("test")},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wrong type",
|
|
||||||
args{[]byte("test"), &alg{}},
|
|
||||||
nil,
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@ -208,66 +196,3 @@ func TestDecryptString(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHash(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
value []byte
|
|
||||||
c HashAlgorithm
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want *CryptoValue
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"ok",
|
|
||||||
args{[]byte("test"), &mockHashCrypto{}},
|
|
||||||
&CryptoValue{CryptoType: TypeHash, Algorithm: "hash", Crypted: []byte("test")},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
got, err := Hash(tt.args.value, tt.args.c)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Hash() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("Hash() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCompareHash(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
value *CryptoValue
|
|
||||||
comparer []byte
|
|
||||||
c HashAlgorithm
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"ok",
|
|
||||||
args{&CryptoValue{CryptoType: TypeHash, Algorithm: "hash", Crypted: []byte("test")}, []byte("test"), &mockHashCrypto{}},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"wrong",
|
|
||||||
args{&CryptoValue{CryptoType: TypeHash, Algorithm: "hash", Crypted: []byte("test")}, []byte("test2"), &mockHashCrypto{}},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if err := CompareHash(tt.args.value, tt.args.comparer, tt.args.c); (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("CompareHash() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -16,12 +16,12 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PasswordHasher struct {
|
type Hasher struct {
|
||||||
*passwap.Swapper
|
*passwap.Swapper
|
||||||
Prefixes []string
|
Prefixes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *PasswordHasher) EncodingSupported(encodedHash string) bool {
|
func (h *Hasher) EncodingSupported(encodedHash string) bool {
|
||||||
for _, prefix := range h.Prefixes {
|
for _, prefix := range h.Prefixes {
|
||||||
if strings.HasPrefix(encodedHash, prefix) {
|
if strings.HasPrefix(encodedHash, prefix) {
|
||||||
return true
|
return true
|
||||||
@ -54,12 +54,12 @@ const (
|
|||||||
HashModeSHA512 HashMode = "sha512"
|
HashModeSHA512 HashMode = "sha512"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PasswordHashConfig struct {
|
type HashConfig struct {
|
||||||
Verifiers []HashName
|
Verifiers []HashName
|
||||||
Hasher HasherConfig
|
Hasher HasherConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PasswordHashConfig) PasswordHasher() (*PasswordHasher, error) {
|
func (c *HashConfig) NewHasher() (*Hasher, error) {
|
||||||
verifiers, vPrefixes, err := c.buildVerifiers()
|
verifiers, vPrefixes, err := c.buildVerifiers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInvalidArgument(err, "CRYPT-sahW9", "password hash config invalid")
|
return nil, zerrors.ThrowInvalidArgument(err, "CRYPT-sahW9", "password hash config invalid")
|
||||||
@ -68,7 +68,7 @@ func (c *PasswordHashConfig) PasswordHasher() (*PasswordHasher, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInvalidArgument(err, "CRYPT-Que4r", "password hash config invalid")
|
return nil, zerrors.ThrowInvalidArgument(err, "CRYPT-Que4r", "password hash config invalid")
|
||||||
}
|
}
|
||||||
return &PasswordHasher{
|
return &Hasher{
|
||||||
Swapper: passwap.NewSwapper(hasher, verifiers...),
|
Swapper: passwap.NewSwapper(hasher, verifiers...),
|
||||||
Prefixes: append(hPrefixes, vPrefixes...),
|
Prefixes: append(hPrefixes, vPrefixes...),
|
||||||
}, nil
|
}, nil
|
||||||
@ -105,7 +105,7 @@ var knowVerifiers = map[HashName]prefixVerifier{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PasswordHashConfig) buildVerifiers() (verifiers []verifier.Verifier, prefixes []string, err error) {
|
func (c *HashConfig) buildVerifiers() (verifiers []verifier.Verifier, prefixes []string, err error) {
|
||||||
verifiers = make([]verifier.Verifier, len(c.Verifiers))
|
verifiers = make([]verifier.Verifier, len(c.Verifiers))
|
||||||
prefixes = make([]string, 0, len(c.Verifiers)+1)
|
prefixes = make([]string, 0, len(c.Verifiers)+1)
|
||||||
for i, name := range c.Verifiers {
|
for i, name := range c.Verifiers {
|
||||||
|
@ -49,7 +49,7 @@ func TestPasswordHasher_EncodingSupported(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
h := &PasswordHasher{
|
h := &Hasher{
|
||||||
Prefixes: []string{bcrypt.Prefix, argon2.Prefix},
|
Prefixes: []string{bcrypt.Prefix, argon2.Prefix},
|
||||||
}
|
}
|
||||||
got := h.EncodingSupported(tt.encodedHash)
|
got := h.EncodingSupported(tt.encodedHash)
|
||||||
@ -340,11 +340,11 @@ func TestPasswordHashConfig_PasswordHasher(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
c := &PasswordHashConfig{
|
c := &HashConfig{
|
||||||
Verifiers: tt.fields.Verifiers,
|
Verifiers: tt.fields.Verifiers,
|
||||||
Hasher: tt.fields.Hasher,
|
Hasher: tt.fields.Hasher,
|
||||||
}
|
}
|
||||||
got, err := c.PasswordHasher()
|
got, err := c.NewHasher()
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
return
|
return
|
||||||
|
@ -11,7 +11,7 @@ type APIApp struct {
|
|||||||
AppID string
|
AppID string
|
||||||
AppName string
|
AppName string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
EncodedHash string
|
||||||
ClientSecretString string
|
ClientSecretString string
|
||||||
AuthMethodType APIAuthMethodType
|
AuthMethodType APIAuthMethodType
|
||||||
|
|
||||||
@ -41,21 +41,21 @@ func (a *APIApp) setClientID(clientID string) {
|
|||||||
a.ClientID = clientID
|
a.ClientID = clientID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIApp) setClientSecret(clientSecret *crypto.CryptoValue) {
|
func (a *APIApp) setClientSecret(encodedHash string) {
|
||||||
a.ClientSecret = clientSecret
|
a.EncodedHash = encodedHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIApp) requiresClientSecret() bool {
|
func (a *APIApp) requiresClientSecret() bool {
|
||||||
return a.AuthMethodType == APIAuthMethodTypeBasic
|
return a.AuthMethodType == APIAuthMethodTypeBasic
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *APIApp) GenerateClientSecretIfNeeded(generator crypto.Generator) (secret string, err error) {
|
func (a *APIApp) GenerateClientSecretIfNeeded(generator *crypto.HashGenerator) (plain string, err error) {
|
||||||
if a.AuthMethodType == APIAuthMethodTypePrivateKeyJWT {
|
if a.AuthMethodType == APIAuthMethodTypePrivateKeyJWT {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
a.ClientSecret, secret, err = NewClientSecret(generator)
|
a.EncodedHash, plain, err = generator.NewCode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return secret, nil
|
return plain, nil
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/id"
|
"github.com/zitadel/zitadel/internal/id"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type oAuthApplication interface {
|
type oAuthApplication interface {
|
||||||
setClientID(clientID string)
|
setClientID(clientID string)
|
||||||
setClientSecret(secret *crypto.CryptoValue)
|
setClientSecret(encodedHash string)
|
||||||
requiresClientSecret() bool
|
requiresClientSecret() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,23 +33,14 @@ func NewClientID(idGenerator id.Generator, projectName string) (string, error) {
|
|||||||
return fmt.Sprintf("%s@%s", rndID, strings.ReplaceAll(strings.ToLower(projectName), " ", "_")), nil
|
return fmt.Sprintf("%s@%s", rndID, strings.ReplaceAll(strings.ToLower(projectName), " ", "_")), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetNewClientSecretIfNeeded(a oAuthApplication, generator crypto.Generator) (string, error) {
|
func SetNewClientSecretIfNeeded(a oAuthApplication, generate func() (encodedHash, plain string, err error)) (string, error) {
|
||||||
if !a.requiresClientSecret() {
|
if !a.requiresClientSecret() {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
clientSecret, secretString, err := NewClientSecret(generator)
|
encodedHash, plain, err := generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
a.setClientSecret(clientSecret)
|
a.setClientSecret(encodedHash)
|
||||||
return secretString, nil
|
return plain, nil
|
||||||
}
|
|
||||||
|
|
||||||
func NewClientSecret(generator crypto.Generator) (*crypto.CryptoValue, string, error) {
|
|
||||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("MODEL-UpnTI").OnError(err).Error("unable to create client secret")
|
|
||||||
return nil, "", zerrors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret")
|
|
||||||
}
|
|
||||||
return cryptoValue, stringSecret, nil
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ type OIDCApp struct {
|
|||||||
AppID string
|
AppID string
|
||||||
AppName string
|
AppName string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
EncodedHash string
|
||||||
ClientSecretString string
|
ClientSecretString string
|
||||||
RedirectUris []string
|
RedirectUris []string
|
||||||
ResponseTypes []OIDCResponseType
|
ResponseTypes []OIDCResponseType
|
||||||
@ -62,8 +61,8 @@ func (a *OIDCApp) setClientID(clientID string) {
|
|||||||
a.ClientID = clientID
|
a.ClientID = clientID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *OIDCApp) setClientSecret(clientSecret *crypto.CryptoValue) {
|
func (a *OIDCApp) setClientSecret(encodedHash string) {
|
||||||
a.ClientSecret = clientSecret
|
a.EncodedHash = encodedHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *OIDCApp) requiresClientSecret() bool {
|
func (a *OIDCApp) requiresClientSecret() bool {
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
@ -102,10 +104,10 @@ func (u *Human) EnsureDisplayName() {
|
|||||||
u.DisplayName = u.Username
|
u.DisplayName = u.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Human) HashPasswordIfExisting(policy *PasswordComplexityPolicy, hasher *crypto.PasswordHasher, onetime bool) error {
|
func (u *Human) HashPasswordIfExisting(ctx context.Context, policy *PasswordComplexityPolicy, hasher *crypto.Hasher, onetime bool) error {
|
||||||
if u.Password != nil {
|
if u.Password != nil {
|
||||||
u.Password.ChangeRequired = onetime
|
u.Password.ChangeRequired = onetime
|
||||||
return u.Password.HashPasswordIfExisting(policy, hasher)
|
return u.Password.HashPasswordIfExisting(ctx, policy, hasher)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +32,7 @@ type PasswordCode struct {
|
|||||||
NotificationType NotificationType
|
NotificationType NotificationType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Password) HashPasswordIfExisting(policy *PasswordComplexityPolicy, hasher *crypto.PasswordHasher) error {
|
func (p *Password) HashPasswordIfExisting(ctx context.Context, policy *PasswordComplexityPolicy, hasher *crypto.Hasher) error {
|
||||||
if p.SecretString == "" {
|
if p.SecretString == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -40,7 +42,9 @@ func (p *Password) HashPasswordIfExisting(policy *PasswordComplexityPolicy, hash
|
|||||||
if err := policy.Check(p.SecretString); err != nil {
|
if err := policy.Check(p.SecretString); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, spanHash := tracing.NewNamedSpan(ctx, "passwap.Hash")
|
||||||
encoded, err := hasher.Hash(p.SecretString)
|
encoded, err := hasher.Hash(p.SecretString)
|
||||||
|
spanHash.EndWithError(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewMachineClientSecret(generator crypto.Generator) (*crypto.CryptoValue, string, error) {
|
|
||||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", zerrors.ThrowInternal(err, "MODEL-57cjsiw", "Errors.User.Machine.Secret.CouldNotGenerate")
|
|
||||||
}
|
|
||||||
return cryptoValue, stringSecret, nil
|
|
||||||
}
|
|
@ -15,98 +15,98 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps6.id,` +
|
expectedAppQuery = regexp.QuoteMeta(`SELECT projections.apps7.id,` +
|
||||||
` projections.apps6.name,` +
|
` projections.apps7.name,` +
|
||||||
` projections.apps6.project_id,` +
|
` projections.apps7.project_id,` +
|
||||||
` projections.apps6.creation_date,` +
|
` projections.apps7.creation_date,` +
|
||||||
` projections.apps6.change_date,` +
|
` projections.apps7.change_date,` +
|
||||||
` projections.apps6.resource_owner,` +
|
` projections.apps7.resource_owner,` +
|
||||||
` projections.apps6.state,` +
|
` projections.apps7.state,` +
|
||||||
` projections.apps6.sequence,` +
|
` projections.apps7.sequence,` +
|
||||||
// api config
|
// api config
|
||||||
` projections.apps6_api_configs.app_id,` +
|
` projections.apps7_api_configs.app_id,` +
|
||||||
` projections.apps6_api_configs.client_id,` +
|
` projections.apps7_api_configs.client_id,` +
|
||||||
` projections.apps6_api_configs.auth_method,` +
|
` projections.apps7_api_configs.auth_method,` +
|
||||||
// oidc config
|
// oidc config
|
||||||
` projections.apps6_oidc_configs.app_id,` +
|
` projections.apps7_oidc_configs.app_id,` +
|
||||||
` projections.apps6_oidc_configs.version,` +
|
` projections.apps7_oidc_configs.version,` +
|
||||||
` projections.apps6_oidc_configs.client_id,` +
|
` projections.apps7_oidc_configs.client_id,` +
|
||||||
` projections.apps6_oidc_configs.redirect_uris,` +
|
` projections.apps7_oidc_configs.redirect_uris,` +
|
||||||
` projections.apps6_oidc_configs.response_types,` +
|
` projections.apps7_oidc_configs.response_types,` +
|
||||||
` projections.apps6_oidc_configs.grant_types,` +
|
` projections.apps7_oidc_configs.grant_types,` +
|
||||||
` projections.apps6_oidc_configs.application_type,` +
|
` projections.apps7_oidc_configs.application_type,` +
|
||||||
` projections.apps6_oidc_configs.auth_method_type,` +
|
` projections.apps7_oidc_configs.auth_method_type,` +
|
||||||
` projections.apps6_oidc_configs.post_logout_redirect_uris,` +
|
` projections.apps7_oidc_configs.post_logout_redirect_uris,` +
|
||||||
` projections.apps6_oidc_configs.is_dev_mode,` +
|
` projections.apps7_oidc_configs.is_dev_mode,` +
|
||||||
` projections.apps6_oidc_configs.access_token_type,` +
|
` projections.apps7_oidc_configs.access_token_type,` +
|
||||||
` projections.apps6_oidc_configs.access_token_role_assertion,` +
|
` projections.apps7_oidc_configs.access_token_role_assertion,` +
|
||||||
` projections.apps6_oidc_configs.id_token_role_assertion,` +
|
` projections.apps7_oidc_configs.id_token_role_assertion,` +
|
||||||
` projections.apps6_oidc_configs.id_token_userinfo_assertion,` +
|
` projections.apps7_oidc_configs.id_token_userinfo_assertion,` +
|
||||||
` projections.apps6_oidc_configs.clock_skew,` +
|
` projections.apps7_oidc_configs.clock_skew,` +
|
||||||
` projections.apps6_oidc_configs.additional_origins,` +
|
` projections.apps7_oidc_configs.additional_origins,` +
|
||||||
` projections.apps6_oidc_configs.skip_native_app_success_page,` +
|
` projections.apps7_oidc_configs.skip_native_app_success_page,` +
|
||||||
//saml config
|
//saml config
|
||||||
` projections.apps6_saml_configs.app_id,` +
|
` projections.apps7_saml_configs.app_id,` +
|
||||||
` projections.apps6_saml_configs.entity_id,` +
|
` projections.apps7_saml_configs.entity_id,` +
|
||||||
` projections.apps6_saml_configs.metadata,` +
|
` projections.apps7_saml_configs.metadata,` +
|
||||||
` projections.apps6_saml_configs.metadata_url` +
|
` projections.apps7_saml_configs.metadata_url` +
|
||||||
` FROM projections.apps6` +
|
` FROM projections.apps7` +
|
||||||
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
|
` LEFT JOIN projections.apps7_api_configs ON projections.apps7.id = projections.apps7_api_configs.app_id AND projections.apps7.instance_id = projections.apps7_api_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
|
` LEFT JOIN projections.apps7_oidc_configs ON projections.apps7.id = projections.apps7_oidc_configs.app_id AND projections.apps7.instance_id = projections.apps7_oidc_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
|
` LEFT JOIN projections.apps7_saml_configs ON projections.apps7.id = projections.apps7_saml_configs.app_id AND projections.apps7.instance_id = projections.apps7_saml_configs.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps6.id,` +
|
expectedAppsQuery = regexp.QuoteMeta(`SELECT projections.apps7.id,` +
|
||||||
` projections.apps6.name,` +
|
` projections.apps7.name,` +
|
||||||
` projections.apps6.project_id,` +
|
` projections.apps7.project_id,` +
|
||||||
` projections.apps6.creation_date,` +
|
` projections.apps7.creation_date,` +
|
||||||
` projections.apps6.change_date,` +
|
` projections.apps7.change_date,` +
|
||||||
` projections.apps6.resource_owner,` +
|
` projections.apps7.resource_owner,` +
|
||||||
` projections.apps6.state,` +
|
` projections.apps7.state,` +
|
||||||
` projections.apps6.sequence,` +
|
` projections.apps7.sequence,` +
|
||||||
// api config
|
// api config
|
||||||
` projections.apps6_api_configs.app_id,` +
|
` projections.apps7_api_configs.app_id,` +
|
||||||
` projections.apps6_api_configs.client_id,` +
|
` projections.apps7_api_configs.client_id,` +
|
||||||
` projections.apps6_api_configs.auth_method,` +
|
` projections.apps7_api_configs.auth_method,` +
|
||||||
// oidc config
|
// oidc config
|
||||||
` projections.apps6_oidc_configs.app_id,` +
|
` projections.apps7_oidc_configs.app_id,` +
|
||||||
` projections.apps6_oidc_configs.version,` +
|
` projections.apps7_oidc_configs.version,` +
|
||||||
` projections.apps6_oidc_configs.client_id,` +
|
` projections.apps7_oidc_configs.client_id,` +
|
||||||
` projections.apps6_oidc_configs.redirect_uris,` +
|
` projections.apps7_oidc_configs.redirect_uris,` +
|
||||||
` projections.apps6_oidc_configs.response_types,` +
|
` projections.apps7_oidc_configs.response_types,` +
|
||||||
` projections.apps6_oidc_configs.grant_types,` +
|
` projections.apps7_oidc_configs.grant_types,` +
|
||||||
` projections.apps6_oidc_configs.application_type,` +
|
` projections.apps7_oidc_configs.application_type,` +
|
||||||
` projections.apps6_oidc_configs.auth_method_type,` +
|
` projections.apps7_oidc_configs.auth_method_type,` +
|
||||||
` projections.apps6_oidc_configs.post_logout_redirect_uris,` +
|
` projections.apps7_oidc_configs.post_logout_redirect_uris,` +
|
||||||
` projections.apps6_oidc_configs.is_dev_mode,` +
|
` projections.apps7_oidc_configs.is_dev_mode,` +
|
||||||
` projections.apps6_oidc_configs.access_token_type,` +
|
` projections.apps7_oidc_configs.access_token_type,` +
|
||||||
` projections.apps6_oidc_configs.access_token_role_assertion,` +
|
` projections.apps7_oidc_configs.access_token_role_assertion,` +
|
||||||
` projections.apps6_oidc_configs.id_token_role_assertion,` +
|
` projections.apps7_oidc_configs.id_token_role_assertion,` +
|
||||||
` projections.apps6_oidc_configs.id_token_userinfo_assertion,` +
|
` projections.apps7_oidc_configs.id_token_userinfo_assertion,` +
|
||||||
` projections.apps6_oidc_configs.clock_skew,` +
|
` projections.apps7_oidc_configs.clock_skew,` +
|
||||||
` projections.apps6_oidc_configs.additional_origins,` +
|
` projections.apps7_oidc_configs.additional_origins,` +
|
||||||
` projections.apps6_oidc_configs.skip_native_app_success_page,` +
|
` projections.apps7_oidc_configs.skip_native_app_success_page,` +
|
||||||
//saml config
|
//saml config
|
||||||
` projections.apps6_saml_configs.app_id,` +
|
` projections.apps7_saml_configs.app_id,` +
|
||||||
` projections.apps6_saml_configs.entity_id,` +
|
` projections.apps7_saml_configs.entity_id,` +
|
||||||
` projections.apps6_saml_configs.metadata,` +
|
` projections.apps7_saml_configs.metadata,` +
|
||||||
` projections.apps6_saml_configs.metadata_url,` +
|
` projections.apps7_saml_configs.metadata_url,` +
|
||||||
` COUNT(*) OVER ()` +
|
` COUNT(*) OVER ()` +
|
||||||
` FROM projections.apps6` +
|
` FROM projections.apps7` +
|
||||||
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
|
` LEFT JOIN projections.apps7_api_configs ON projections.apps7.id = projections.apps7_api_configs.app_id AND projections.apps7.instance_id = projections.apps7_api_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
|
` LEFT JOIN projections.apps7_oidc_configs ON projections.apps7.id = projections.apps7_oidc_configs.app_id AND projections.apps7.instance_id = projections.apps7_oidc_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
|
` LEFT JOIN projections.apps7_saml_configs ON projections.apps7.id = projections.apps7_saml_configs.app_id AND projections.apps7.instance_id = projections.apps7_saml_configs.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps6_api_configs.client_id,` +
|
expectedAppIDsQuery = regexp.QuoteMeta(`SELECT projections.apps7_api_configs.client_id,` +
|
||||||
` projections.apps6_oidc_configs.client_id` +
|
` projections.apps7_oidc_configs.client_id` +
|
||||||
` FROM projections.apps6` +
|
` FROM projections.apps7` +
|
||||||
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
|
` LEFT JOIN projections.apps7_api_configs ON projections.apps7.id = projections.apps7_api_configs.app_id AND projections.apps7.instance_id = projections.apps7_api_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
|
` LEFT JOIN projections.apps7_oidc_configs ON projections.apps7.id = projections.apps7_oidc_configs.app_id AND projections.apps7.instance_id = projections.apps7_oidc_configs.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps6.project_id` +
|
expectedProjectIDByAppQuery = regexp.QuoteMeta(`SELECT projections.apps7.project_id` +
|
||||||
` FROM projections.apps6` +
|
` FROM projections.apps7` +
|
||||||
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
|
` LEFT JOIN projections.apps7_api_configs ON projections.apps7.id = projections.apps7_api_configs.app_id AND projections.apps7.instance_id = projections.apps7_api_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
|
` LEFT JOIN projections.apps7_oidc_configs ON projections.apps7.id = projections.apps7_oidc_configs.app_id AND projections.apps7.instance_id = projections.apps7_oidc_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
|
` LEFT JOIN projections.apps7_saml_configs ON projections.apps7.id = projections.apps7_saml_configs.app_id AND projections.apps7.instance_id = projections.apps7_saml_configs.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects4.id,` +
|
expectedProjectByAppQuery = regexp.QuoteMeta(`SELECT projections.projects4.id,` +
|
||||||
` projections.projects4.creation_date,` +
|
` projections.projects4.creation_date,` +
|
||||||
@ -120,10 +120,10 @@ var (
|
|||||||
` projections.projects4.has_project_check,` +
|
` projections.projects4.has_project_check,` +
|
||||||
` projections.projects4.private_labeling_setting` +
|
` projections.projects4.private_labeling_setting` +
|
||||||
` FROM projections.projects4` +
|
` FROM projections.projects4` +
|
||||||
` JOIN projections.apps6 ON projections.projects4.id = projections.apps6.project_id AND projections.projects4.instance_id = projections.apps6.instance_id` +
|
` JOIN projections.apps7 ON projections.projects4.id = projections.apps7.project_id AND projections.projects4.instance_id = projections.apps7.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_api_configs ON projections.apps6.id = projections.apps6_api_configs.app_id AND projections.apps6.instance_id = projections.apps6_api_configs.instance_id` +
|
` LEFT JOIN projections.apps7_api_configs ON projections.apps7.id = projections.apps7_api_configs.app_id AND projections.apps7.instance_id = projections.apps7_api_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_oidc_configs ON projections.apps6.id = projections.apps6_oidc_configs.app_id AND projections.apps6.instance_id = projections.apps6_oidc_configs.instance_id` +
|
` LEFT JOIN projections.apps7_oidc_configs ON projections.apps7.id = projections.apps7_oidc_configs.app_id AND projections.apps7.instance_id = projections.apps7_oidc_configs.instance_id` +
|
||||||
` LEFT JOIN projections.apps6_saml_configs ON projections.apps6.id = projections.apps6_saml_configs.app_id AND projections.apps6.instance_id = projections.apps6_saml_configs.instance_id` +
|
` LEFT JOIN projections.apps7_saml_configs ON projections.apps7.id = projections.apps7_saml_configs.app_id AND projections.apps7.instance_id = projections.apps7_saml_configs.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
|
|
||||||
appCols = database.TextArray[string]{
|
appCols = database.TextArray[string]{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
with config as (
|
with config as (
|
||||||
select app_id, client_id, client_secret
|
select app_id, client_id, client_secret, 'api' as app_type
|
||||||
from projections.apps6_api_configs
|
from projections.apps7_api_configs
|
||||||
where instance_id = $1
|
where instance_id = $1
|
||||||
and client_id = $2
|
and client_id = $2
|
||||||
union
|
union
|
||||||
select app_id, client_id, client_secret
|
select app_id, client_id, client_secret, 'oidc' as app_type
|
||||||
from projections.apps6_oidc_configs
|
from projections.apps7_oidc_configs
|
||||||
where instance_id = $1
|
where instance_id = $1
|
||||||
and client_id = $2
|
and client_id = $2
|
||||||
),
|
),
|
||||||
@ -18,6 +18,7 @@ keys as (
|
|||||||
and expiration > current_timestamp
|
and expiration > current_timestamp
|
||||||
group by identifier
|
group by identifier
|
||||||
)
|
)
|
||||||
select config.client_id, config.client_secret, apps.project_id, keys.public_keys from config
|
select config.app_id, config.client_id, config.client_secret, config.app_type, apps.project_id, apps.resource_owner, keys.public_keys
|
||||||
join projections.apps6 apps on apps.id = config.app_id
|
from config
|
||||||
|
join projections.apps7 apps on apps.id = config.app_id
|
||||||
left join keys on keys.client_id = config.client_id;
|
left join keys on keys.client_id = config.client_id;
|
||||||
|
@ -7,8 +7,8 @@ with client as (
|
|||||||
c.application_type, c.auth_method_type, c.post_logout_redirect_uris, c.is_dev_mode,
|
c.application_type, c.auth_method_type, c.post_logout_redirect_uris, c.is_dev_mode,
|
||||||
c.access_token_type, c.access_token_role_assertion, c.id_token_role_assertion,
|
c.access_token_type, c.access_token_role_assertion, c.id_token_role_assertion,
|
||||||
c.id_token_userinfo_assertion, c.clock_skew, c.additional_origins, a.project_id, a.state
|
c.id_token_userinfo_assertion, c.clock_skew, c.additional_origins, a.project_id, a.state
|
||||||
from projections.apps6_oidc_configs c
|
from projections.apps7_oidc_configs c
|
||||||
join projections.apps6 a on a.id = c.app_id and a.instance_id = c.instance_id
|
join projections.apps7 a on a.id = c.app_id and a.instance_id = c.instance_id
|
||||||
where c.instance_id = $1
|
where c.instance_id = $1
|
||||||
and c.client_id = $2
|
and c.client_id = $2
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
with usr as (
|
with usr as (
|
||||||
select u.id, u.creation_date, u.change_date, u.sequence, u.state, u.resource_owner, u.username, n.login_name as preferred_login_name
|
select u.id, u.creation_date, u.change_date, u.sequence, u.state, u.resource_owner, u.username, n.login_name as preferred_login_name
|
||||||
from projections.users11 u
|
from projections.users12 u
|
||||||
left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id
|
left join projections.login_names3 n on u.id = n.user_id and u.instance_id = n.instance_id
|
||||||
where u.id = $1
|
where u.id = $1
|
||||||
and u.instance_id = $2
|
and u.instance_id = $2
|
||||||
@ -9,7 +9,7 @@ with usr as (
|
|||||||
human as (
|
human as (
|
||||||
select $1 as user_id, row_to_json(r) as human from (
|
select $1 as user_id, row_to_json(r) as human from (
|
||||||
select first_name, last_name, nick_name, display_name, avatar_key, preferred_language, gender, email, is_email_verified, phone, is_phone_verified
|
select first_name, last_name, nick_name, display_name, avatar_key, preferred_language, gender, email, is_email_verified, phone, is_phone_verified
|
||||||
from projections.users11_humans
|
from projections.users12_humans
|
||||||
where user_id = $1
|
where user_id = $1
|
||||||
and instance_id = $2
|
and instance_id = $2
|
||||||
) r
|
) r
|
||||||
@ -17,7 +17,7 @@ human as (
|
|||||||
machine as (
|
machine as (
|
||||||
select $1 as user_id, row_to_json(r) as machine from (
|
select $1 as user_id, row_to_json(r) as machine from (
|
||||||
select name, description
|
select name, description
|
||||||
from projections.users11_machines
|
from projections.users12_machines
|
||||||
where user_id = $1
|
where user_id = $1
|
||||||
and instance_id = $2
|
and instance_id = $2
|
||||||
) r
|
) r
|
||||||
|
@ -21,21 +21,21 @@ var (
|
|||||||
", members.user_id" +
|
", members.user_id" +
|
||||||
", members.roles" +
|
", members.roles" +
|
||||||
", projections.login_names3.login_name" +
|
", projections.login_names3.login_name" +
|
||||||
", projections.users11_humans.email" +
|
", projections.users12_humans.email" +
|
||||||
", projections.users11_humans.first_name" +
|
", projections.users12_humans.first_name" +
|
||||||
", projections.users11_humans.last_name" +
|
", projections.users12_humans.last_name" +
|
||||||
", projections.users11_humans.display_name" +
|
", projections.users12_humans.display_name" +
|
||||||
", projections.users11_machines.name" +
|
", projections.users12_machines.name" +
|
||||||
", projections.users11_humans.avatar_key" +
|
", projections.users12_humans.avatar_key" +
|
||||||
", projections.users11.type" +
|
", projections.users12.type" +
|
||||||
", COUNT(*) OVER () " +
|
", COUNT(*) OVER () " +
|
||||||
"FROM projections.instance_members4 AS members " +
|
"FROM projections.instance_members4 AS members " +
|
||||||
"LEFT JOIN projections.users11_humans " +
|
"LEFT JOIN projections.users12_humans " +
|
||||||
"ON members.user_id = projections.users11_humans.user_id AND members.instance_id = projections.users11_humans.instance_id " +
|
"ON members.user_id = projections.users12_humans.user_id AND members.instance_id = projections.users12_humans.instance_id " +
|
||||||
"LEFT JOIN projections.users11_machines " +
|
"LEFT JOIN projections.users12_machines " +
|
||||||
"ON members.user_id = projections.users11_machines.user_id AND members.instance_id = projections.users11_machines.instance_id " +
|
"ON members.user_id = projections.users12_machines.user_id AND members.instance_id = projections.users12_machines.instance_id " +
|
||||||
"LEFT JOIN projections.users11 " +
|
"LEFT JOIN projections.users12 " +
|
||||||
"ON members.user_id = projections.users11.id AND members.instance_id = projections.users11.instance_id " +
|
"ON members.user_id = projections.users12.id AND members.instance_id = projections.users12.instance_id " +
|
||||||
"LEFT JOIN projections.login_names3 " +
|
"LEFT JOIN projections.login_names3 " +
|
||||||
"ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " +
|
"ON members.user_id = projections.login_names3.user_id AND members.instance_id = projections.login_names3.instance_id " +
|
||||||
"AS OF SYSTEM TIME '-1 ms' " +
|
"AS OF SYSTEM TIME '-1 ms' " +
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
"github.com/zitadel/zitadel/internal/query/projection"
|
"github.com/zitadel/zitadel/internal/query/projection"
|
||||||
@ -30,10 +29,20 @@ func TriggerIntrospectionProjections(ctx context.Context) {
|
|||||||
triggerBatch(ctx, introspectionTriggerHandlers()...)
|
triggerBatch(ctx, introspectionTriggerHandlers()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AppType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AppTypeAPI = "api"
|
||||||
|
AppTypeOIDC = "oidc"
|
||||||
|
)
|
||||||
|
|
||||||
type IntrospectionClient struct {
|
type IntrospectionClient struct {
|
||||||
|
AppID string
|
||||||
ClientID string
|
ClientID string
|
||||||
ClientSecret *crypto.CryptoValue
|
HashedSecret string
|
||||||
|
AppType AppType
|
||||||
ProjectID string
|
ProjectID string
|
||||||
|
ResourceOwner string
|
||||||
PublicKeys database.Map[[]byte]
|
PublicKeys database.Map[[]byte]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +59,15 @@ func (q *Queries) GetIntrospectionClientByID(ctx context.Context, clientID strin
|
|||||||
)
|
)
|
||||||
|
|
||||||
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
||||||
return row.Scan(&client.ClientID, &client.ClientSecret, &client.ProjectID, &client.PublicKeys)
|
return row.Scan(
|
||||||
|
&client.AppID,
|
||||||
|
&client.ClientID,
|
||||||
|
&client.HashedSecret,
|
||||||
|
&client.AppType,
|
||||||
|
&client.ProjectID,
|
||||||
|
&client.ResourceOwner,
|
||||||
|
&client.PublicKeys,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
introspectionClientByIDQuery,
|
introspectionClientByIDQuery,
|
||||||
instanceID, clientID, getKeys,
|
instanceID, clientID, getKeys,
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/json"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -12,20 +11,10 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQueries_GetIntrospectionClientByID(t *testing.T) {
|
func TestQueries_GetIntrospectionClientByID(t *testing.T) {
|
||||||
secret := &crypto.CryptoValue{
|
|
||||||
CryptoType: crypto.TypeHash,
|
|
||||||
Algorithm: "alg",
|
|
||||||
KeyID: "keyID",
|
|
||||||
Crypted: []byte("secret"),
|
|
||||||
}
|
|
||||||
encSecret, err := json.Marshal(secret)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
pubkeys := database.Map[[]byte]{
|
pubkeys := database.Map[[]byte]{
|
||||||
"key1": {1, 2, 3},
|
"key1": {1, 2, 3},
|
||||||
"key2": {4, 5, 6},
|
"key2": {4, 5, 6},
|
||||||
@ -61,13 +50,16 @@ func TestQueries_GetIntrospectionClientByID(t *testing.T) {
|
|||||||
getKeys: false,
|
getKeys: false,
|
||||||
},
|
},
|
||||||
mock: mockQuery(expQuery,
|
mock: mockQuery(expQuery,
|
||||||
[]string{"client_id", "client_secret", "project_id", "public_keys"},
|
[]string{"app_id", "client_id", "client_secret", "app_type", "project_id", "resource_owner", "public_keys"},
|
||||||
[]driver.Value{"clientID", encSecret, "projectID", nil},
|
[]driver.Value{"appID", "clientID", "secret", "oidc", "projectID", "orgID", nil},
|
||||||
"instanceID", "clientID", false),
|
"instanceID", "clientID", false),
|
||||||
want: &IntrospectionClient{
|
want: &IntrospectionClient{
|
||||||
|
AppID: "appID",
|
||||||
ClientID: "clientID",
|
ClientID: "clientID",
|
||||||
ClientSecret: secret,
|
HashedSecret: "secret",
|
||||||
|
AppType: AppTypeOIDC,
|
||||||
ProjectID: "projectID",
|
ProjectID: "projectID",
|
||||||
|
ResourceOwner: "orgID",
|
||||||
PublicKeys: nil,
|
PublicKeys: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -78,13 +70,16 @@ func TestQueries_GetIntrospectionClientByID(t *testing.T) {
|
|||||||
getKeys: true,
|
getKeys: true,
|
||||||
},
|
},
|
||||||
mock: mockQuery(expQuery,
|
mock: mockQuery(expQuery,
|
||||||
[]string{"client_id", "client_secret", "project_id", "public_keys"},
|
[]string{"app_id", "client_id", "client_secret", "app_type", "project_id", "resource_owner", "public_keys"},
|
||||||
[]driver.Value{"clientID", nil, "projectID", encPubkeys},
|
[]driver.Value{"appID", "clientID", "", "oidc", "projectID", "orgID", encPubkeys},
|
||||||
"instanceID", "clientID", true),
|
"instanceID", "clientID", true),
|
||||||
want: &IntrospectionClient{
|
want: &IntrospectionClient{
|
||||||
|
AppID: "appID",
|
||||||
ClientID: "clientID",
|
ClientID: "clientID",
|
||||||
ClientSecret: nil,
|
HashedSecret: "",
|
||||||
|
AppType: AppTypeOIDC,
|
||||||
ProjectID: "projectID",
|
ProjectID: "projectID",
|
||||||
|
ResourceOwner: "orgID",
|
||||||
PublicKeys: pubkeys,
|
PublicKeys: pubkeys,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
@ -20,7 +19,7 @@ type OIDCClient struct {
|
|||||||
AppID string `json:"app_id,omitempty"`
|
AppID string `json:"app_id,omitempty"`
|
||||||
State domain.AppState `json:"state,omitempty"`
|
State domain.AppState `json:"state,omitempty"`
|
||||||
ClientID string `json:"client_id,omitempty"`
|
ClientID string `json:"client_id,omitempty"`
|
||||||
ClientSecret *crypto.CryptoValue `json:"client_secret,omitempty"`
|
HashedSecret string `json:"client_secret,omitempty"`
|
||||||
RedirectURIs []string `json:"redirect_uris,omitempty"`
|
RedirectURIs []string `json:"redirect_uris,omitempty"`
|
||||||
ResponseTypes []domain.OIDCResponseType `json:"response_types,omitempty"`
|
ResponseTypes []domain.OIDCResponseType `json:"response_types,omitempty"`
|
||||||
GrantTypes []domain.OIDCGrantType `json:"grant_types,omitempty"`
|
GrantTypes []domain.OIDCGrantType `json:"grant_types,omitempty"`
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
@ -66,7 +65,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
|||||||
AppID: "236647088211886082",
|
AppID: "236647088211886082",
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
ClientID: "236647088211951618@tests",
|
ClientID: "236647088211951618@tests",
|
||||||
ClientSecret: nil,
|
HashedSecret: "",
|
||||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode, domain.OIDCGrantTypeRefreshToken},
|
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode, domain.OIDCGrantTypeRefreshToken},
|
||||||
@ -97,7 +96,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
|||||||
AppID: "236646457053020162",
|
AppID: "236646457053020162",
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
ClientID: "236646457053085698@tests",
|
ClientID: "236646457053085698@tests",
|
||||||
ClientSecret: nil,
|
HashedSecret: "",
|
||||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
@ -128,11 +127,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
|||||||
AppID: "236646858984783874",
|
AppID: "236646858984783874",
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
ClientID: "236646858984849410@tests",
|
ClientID: "236646858984849410@tests",
|
||||||
ClientSecret: &crypto.CryptoValue{
|
HashedSecret: "$2a$14$OzZ0XEZZEtD13py/EPba2evsS6WcKZ5orVMj9pWHEGEHmLu2h3PFq",
|
||||||
CryptoType: crypto.TypeHash,
|
|
||||||
Algorithm: "bcrypt",
|
|
||||||
Crypted: []byte(`$2a$14$OzZ0XEZZEtD13py/EPba2evsS6WcKZ5orVMj9pWHEGEHmLu2h3PFq`),
|
|
||||||
},
|
|
||||||
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
RedirectURIs: []string{"http://localhost:9999/auth/callback"},
|
||||||
ResponseTypes: []domain.OIDCResponseType{0},
|
ResponseTypes: []domain.OIDCResponseType{0},
|
||||||
GrantTypes: []domain.OIDCGrantType{0},
|
GrantTypes: []domain.OIDCGrantType{0},
|
||||||
@ -163,7 +158,7 @@ low2kyJov38V4Uk2I8kuXpLcnrpw5Tio2ooiUE27b0vHZqBKOei9Uo88qCrn3EKx
|
|||||||
AppID: "239520764276441090",
|
AppID: "239520764276441090",
|
||||||
State: domain.AppStateActive,
|
State: domain.AppStateActive,
|
||||||
ClientID: "239520764779364354@zitadel",
|
ClientID: "239520764779364354@zitadel",
|
||||||
ClientSecret: nil,
|
HashedSecret: "",
|
||||||
RedirectURIs: []string{
|
RedirectURIs: []string{
|
||||||
"http://test2-qucuh5.localhost:9000/ui/console/auth/callback",
|
"http://test2-qucuh5.localhost:9000/ui/console/auth/callback",
|
||||||
"http://test.localhost.com:9000/ui/console/auth/callback"},
|
"http://test.localhost.com:9000/ui/console/auth/callback"},
|
||||||
|
@ -21,24 +21,24 @@ var (
|
|||||||
", members.user_id" +
|
", members.user_id" +
|
||||||
", members.roles" +
|
", members.roles" +
|
||||||
", projections.login_names3.login_name" +
|
", projections.login_names3.login_name" +
|
||||||
", projections.users11_humans.email" +
|
", projections.users12_humans.email" +
|
||||||
", projections.users11_humans.first_name" +
|
", projections.users12_humans.first_name" +
|
||||||
", projections.users11_humans.last_name" +
|
", projections.users12_humans.last_name" +
|
||||||
", projections.users11_humans.display_name" +
|
", projections.users12_humans.display_name" +
|
||||||
", projections.users11_machines.name" +
|
", projections.users12_machines.name" +
|
||||||
", projections.users11_humans.avatar_key" +
|
", projections.users12_humans.avatar_key" +
|
||||||
", projections.users11.type" +
|
", projections.users12.type" +
|
||||||
", COUNT(*) OVER () " +
|
", COUNT(*) OVER () " +
|
||||||
"FROM projections.org_members4 AS members " +
|
"FROM projections.org_members4 AS members " +
|
||||||
"LEFT JOIN projections.users11_humans " +
|
"LEFT JOIN projections.users12_humans " +
|
||||||
"ON members.user_id = projections.users11_humans.user_id " +
|
"ON members.user_id = projections.users12_humans.user_id " +
|
||||||
"AND members.instance_id = projections.users11_humans.instance_id " +
|
"AND members.instance_id = projections.users12_humans.instance_id " +
|
||||||
"LEFT JOIN projections.users11_machines " +
|
"LEFT JOIN projections.users12_machines " +
|
||||||
"ON members.user_id = projections.users11_machines.user_id " +
|
"ON members.user_id = projections.users12_machines.user_id " +
|
||||||
"AND members.instance_id = projections.users11_machines.instance_id " +
|
"AND members.instance_id = projections.users12_machines.instance_id " +
|
||||||
"LEFT JOIN projections.users11 " +
|
"LEFT JOIN projections.users12 " +
|
||||||
"ON members.user_id = projections.users11.id " +
|
"ON members.user_id = projections.users12.id " +
|
||||||
"AND members.instance_id = projections.users11.instance_id " +
|
"AND members.instance_id = projections.users12.instance_id " +
|
||||||
"LEFT JOIN projections.login_names3 " +
|
"LEFT JOIN projections.login_names3 " +
|
||||||
"ON members.user_id = projections.login_names3.user_id " +
|
"ON members.user_id = projections.login_names3.user_id " +
|
||||||
"AND members.instance_id = projections.login_names3.instance_id " +
|
"AND members.instance_id = projections.login_names3.instance_id " +
|
||||||
|
@ -21,24 +21,24 @@ var (
|
|||||||
", members.user_id" +
|
", members.user_id" +
|
||||||
", members.roles" +
|
", members.roles" +
|
||||||
", projections.login_names3.login_name" +
|
", projections.login_names3.login_name" +
|
||||||
", projections.users11_humans.email" +
|
", projections.users12_humans.email" +
|
||||||
", projections.users11_humans.first_name" +
|
", projections.users12_humans.first_name" +
|
||||||
", projections.users11_humans.last_name" +
|
", projections.users12_humans.last_name" +
|
||||||
", projections.users11_humans.display_name" +
|
", projections.users12_humans.display_name" +
|
||||||
", projections.users11_machines.name" +
|
", projections.users12_machines.name" +
|
||||||
", projections.users11_humans.avatar_key" +
|
", projections.users12_humans.avatar_key" +
|
||||||
", projections.users11.type" +
|
", projections.users12.type" +
|
||||||
", COUNT(*) OVER () " +
|
", COUNT(*) OVER () " +
|
||||||
"FROM projections.project_grant_members4 AS members " +
|
"FROM projections.project_grant_members4 AS members " +
|
||||||
"LEFT JOIN projections.users11_humans " +
|
"LEFT JOIN projections.users12_humans " +
|
||||||
"ON members.user_id = projections.users11_humans.user_id " +
|
"ON members.user_id = projections.users12_humans.user_id " +
|
||||||
"AND members.instance_id = projections.users11_humans.instance_id " +
|
"AND members.instance_id = projections.users12_humans.instance_id " +
|
||||||
"LEFT JOIN projections.users11_machines " +
|
"LEFT JOIN projections.users12_machines " +
|
||||||
"ON members.user_id = projections.users11_machines.user_id " +
|
"ON members.user_id = projections.users12_machines.user_id " +
|
||||||
"AND members.instance_id = projections.users11_machines.instance_id " +
|
"AND members.instance_id = projections.users12_machines.instance_id " +
|
||||||
"LEFT JOIN projections.users11 " +
|
"LEFT JOIN projections.users12 " +
|
||||||
"ON members.user_id = projections.users11.id " +
|
"ON members.user_id = projections.users12.id " +
|
||||||
"AND members.instance_id = projections.users11.instance_id " +
|
"AND members.instance_id = projections.users12.instance_id " +
|
||||||
"LEFT JOIN projections.login_names3 " +
|
"LEFT JOIN projections.login_names3 " +
|
||||||
"ON members.user_id = projections.login_names3.user_id " +
|
"ON members.user_id = projections.login_names3.user_id " +
|
||||||
"AND members.instance_id = projections.login_names3.instance_id " +
|
"AND members.instance_id = projections.login_names3.instance_id " +
|
||||||
|
@ -21,24 +21,24 @@ var (
|
|||||||
", members.user_id" +
|
", members.user_id" +
|
||||||
", members.roles" +
|
", members.roles" +
|
||||||
", projections.login_names3.login_name" +
|
", projections.login_names3.login_name" +
|
||||||
", projections.users11_humans.email" +
|
", projections.users12_humans.email" +
|
||||||
", projections.users11_humans.first_name" +
|
", projections.users12_humans.first_name" +
|
||||||
", projections.users11_humans.last_name" +
|
", projections.users12_humans.last_name" +
|
||||||
", projections.users11_humans.display_name" +
|
", projections.users12_humans.display_name" +
|
||||||
", projections.users11_machines.name" +
|
", projections.users12_machines.name" +
|
||||||
", projections.users11_humans.avatar_key" +
|
", projections.users12_humans.avatar_key" +
|
||||||
", projections.users11.type" +
|
", projections.users12.type" +
|
||||||
", COUNT(*) OVER () " +
|
", COUNT(*) OVER () " +
|
||||||
"FROM projections.project_members4 AS members " +
|
"FROM projections.project_members4 AS members " +
|
||||||
"LEFT JOIN projections.users11_humans " +
|
"LEFT JOIN projections.users12_humans " +
|
||||||
"ON members.user_id = projections.users11_humans.user_id " +
|
"ON members.user_id = projections.users12_humans.user_id " +
|
||||||
"AND members.instance_id = projections.users11_humans.instance_id " +
|
"AND members.instance_id = projections.users12_humans.instance_id " +
|
||||||
"LEFT JOIN projections.users11_machines " +
|
"LEFT JOIN projections.users12_machines " +
|
||||||
"ON members.user_id = projections.users11_machines.user_id " +
|
"ON members.user_id = projections.users12_machines.user_id " +
|
||||||
"AND members.instance_id = projections.users11_machines.instance_id " +
|
"AND members.instance_id = projections.users12_machines.instance_id " +
|
||||||
"LEFT JOIN projections.users11 " +
|
"LEFT JOIN projections.users12 " +
|
||||||
"ON members.user_id = projections.users11.id " +
|
"ON members.user_id = projections.users12.id " +
|
||||||
"AND members.instance_id = projections.users11.instance_id " +
|
"AND members.instance_id = projections.users12.instance_id " +
|
||||||
"LEFT JOIN projections.login_names3 " +
|
"LEFT JOIN projections.login_names3 " +
|
||||||
"ON members.user_id = projections.login_names3.user_id " +
|
"ON members.user_id = projections.login_names3.user_id " +
|
||||||
"AND members.instance_id = projections.login_names3.instance_id " +
|
"AND members.instance_id = projections.login_names3.instance_id " +
|
||||||
|
@ -3,6 +3,7 @@ package projection
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AppProjectionTable = "projections.apps6"
|
AppProjectionTable = "projections.apps7"
|
||||||
AppAPITable = AppProjectionTable + "_" + appAPITableSuffix
|
AppAPITable = AppProjectionTable + "_" + appAPITableSuffix
|
||||||
AppOIDCTable = AppProjectionTable + "_" + appOIDCTableSuffix
|
AppOIDCTable = AppProjectionTable + "_" + appOIDCTableSuffix
|
||||||
AppSAMLTable = AppProjectionTable + "_" + appSAMLTableSuffix
|
AppSAMLTable = AppProjectionTable + "_" + appSAMLTableSuffix
|
||||||
@ -96,7 +97,7 @@ func (*appProjection) Init() *old_handler.Check {
|
|||||||
handler.NewColumn(AppAPIConfigColumnAppID, handler.ColumnTypeText),
|
handler.NewColumn(AppAPIConfigColumnAppID, handler.ColumnTypeText),
|
||||||
handler.NewColumn(AppAPIConfigColumnInstanceID, handler.ColumnTypeText),
|
handler.NewColumn(AppAPIConfigColumnInstanceID, handler.ColumnTypeText),
|
||||||
handler.NewColumn(AppAPIConfigColumnClientID, handler.ColumnTypeText),
|
handler.NewColumn(AppAPIConfigColumnClientID, handler.ColumnTypeText),
|
||||||
handler.NewColumn(AppAPIConfigColumnClientSecret, handler.ColumnTypeJSONB, handler.Nullable()),
|
handler.NewColumn(AppAPIConfigColumnClientSecret, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(AppAPIConfigColumnAuthMethod, handler.ColumnTypeEnum),
|
handler.NewColumn(AppAPIConfigColumnAuthMethod, handler.ColumnTypeEnum),
|
||||||
},
|
},
|
||||||
handler.NewPrimaryKey(AppAPIConfigColumnInstanceID, AppAPIConfigColumnAppID),
|
handler.NewPrimaryKey(AppAPIConfigColumnInstanceID, AppAPIConfigColumnAppID),
|
||||||
@ -109,7 +110,7 @@ func (*appProjection) Init() *old_handler.Check {
|
|||||||
handler.NewColumn(AppOIDCConfigColumnInstanceID, handler.ColumnTypeText),
|
handler.NewColumn(AppOIDCConfigColumnInstanceID, handler.ColumnTypeText),
|
||||||
handler.NewColumn(AppOIDCConfigColumnVersion, handler.ColumnTypeEnum),
|
handler.NewColumn(AppOIDCConfigColumnVersion, handler.ColumnTypeEnum),
|
||||||
handler.NewColumn(AppOIDCConfigColumnClientID, handler.ColumnTypeText),
|
handler.NewColumn(AppOIDCConfigColumnClientID, handler.ColumnTypeText),
|
||||||
handler.NewColumn(AppOIDCConfigColumnClientSecret, handler.ColumnTypeJSONB, handler.Nullable()),
|
handler.NewColumn(AppOIDCConfigColumnClientSecret, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(AppOIDCConfigColumnRedirectUris, handler.ColumnTypeTextArray, handler.Nullable()),
|
handler.NewColumn(AppOIDCConfigColumnRedirectUris, handler.ColumnTypeTextArray, handler.Nullable()),
|
||||||
handler.NewColumn(AppOIDCConfigColumnResponseTypes, handler.ColumnTypeEnumArray, handler.Nullable()),
|
handler.NewColumn(AppOIDCConfigColumnResponseTypes, handler.ColumnTypeEnumArray, handler.Nullable()),
|
||||||
handler.NewColumn(AppOIDCConfigColumnGrantTypes, handler.ColumnTypeEnumArray, handler.Nullable()),
|
handler.NewColumn(AppOIDCConfigColumnGrantTypes, handler.ColumnTypeEnumArray, handler.Nullable()),
|
||||||
@ -186,6 +187,10 @@ func (p *appProjection) Reducers() []handler.AggregateReducer {
|
|||||||
Event: project.APIConfigSecretChangedType,
|
Event: project.APIConfigSecretChangedType,
|
||||||
Reduce: p.reduceAPIConfigSecretChanged,
|
Reduce: p.reduceAPIConfigSecretChanged,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: project.APIConfigSecretHashUpdatedType,
|
||||||
|
Reduce: p.reduceAPIConfigSecretHashUpdated,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: project.OIDCConfigAddedType,
|
Event: project.OIDCConfigAddedType,
|
||||||
Reduce: p.reduceOIDCConfigAdded,
|
Reduce: p.reduceOIDCConfigAdded,
|
||||||
@ -198,6 +203,10 @@ func (p *appProjection) Reducers() []handler.AggregateReducer {
|
|||||||
Event: project.OIDCConfigSecretChangedType,
|
Event: project.OIDCConfigSecretChangedType,
|
||||||
Reduce: p.reduceOIDCConfigSecretChanged,
|
Reduce: p.reduceOIDCConfigSecretChanged,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: project.OIDCConfigSecretHashUpdatedType,
|
||||||
|
Reduce: p.reduceOIDCConfigSecretHashUpdated,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: project.SAMLConfigAddedType,
|
Event: project.SAMLConfigAddedType,
|
||||||
Reduce: p.reduceSAMLConfigAdded,
|
Reduce: p.reduceSAMLConfigAdded,
|
||||||
@ -350,7 +359,7 @@ func (p *appProjection) reduceAPIConfigAdded(event eventstore.Event) (*handler.S
|
|||||||
handler.NewCol(AppAPIConfigColumnAppID, e.AppID),
|
handler.NewCol(AppAPIConfigColumnAppID, e.AppID),
|
||||||
handler.NewCol(AppAPIConfigColumnInstanceID, e.Aggregate().InstanceID),
|
handler.NewCol(AppAPIConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
handler.NewCol(AppAPIConfigColumnClientID, e.ClientID),
|
handler.NewCol(AppAPIConfigColumnClientID, e.ClientID),
|
||||||
handler.NewCol(AppAPIConfigColumnClientSecret, e.ClientSecret),
|
handler.NewCol(AppAPIConfigColumnClientSecret, crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)),
|
||||||
handler.NewCol(AppAPIConfigColumnAuthMethod, e.AuthMethodType),
|
handler.NewCol(AppAPIConfigColumnAuthMethod, e.AuthMethodType),
|
||||||
},
|
},
|
||||||
handler.WithTableSuffix(appAPITableSuffix),
|
handler.WithTableSuffix(appAPITableSuffix),
|
||||||
@ -374,9 +383,6 @@ func (p *appProjection) reduceAPIConfigChanged(event eventstore.Event) (*handler
|
|||||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-vnZKi", "reduce.wrong.event.type %s", project.APIConfigChangedType)
|
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-vnZKi", "reduce.wrong.event.type %s", project.APIConfigChangedType)
|
||||||
}
|
}
|
||||||
cols := make([]handler.Column, 0, 2)
|
cols := make([]handler.Column, 0, 2)
|
||||||
if e.ClientSecret != nil {
|
|
||||||
cols = append(cols, handler.NewCol(AppAPIConfigColumnClientSecret, e.ClientSecret))
|
|
||||||
}
|
|
||||||
if e.AuthMethodType != nil {
|
if e.AuthMethodType != nil {
|
||||||
cols = append(cols, handler.NewCol(AppAPIConfigColumnAuthMethod, *e.AuthMethodType))
|
cols = append(cols, handler.NewCol(AppAPIConfigColumnAuthMethod, *e.AuthMethodType))
|
||||||
}
|
}
|
||||||
@ -415,7 +421,37 @@ func (p *appProjection) reduceAPIConfigSecretChanged(event eventstore.Event) (*h
|
|||||||
e,
|
e,
|
||||||
handler.AddUpdateStatement(
|
handler.AddUpdateStatement(
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(AppAPIConfigColumnClientSecret, e.ClientSecret),
|
handler.NewCol(AppAPIConfigColumnClientSecret, crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(AppAPIConfigColumnAppID, e.AppID),
|
||||||
|
handler.NewCond(AppAPIConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
handler.WithTableSuffix(appAPITableSuffix),
|
||||||
|
),
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(AppColumnChangeDate, e.CreationDate()),
|
||||||
|
handler.NewCol(AppColumnSequence, e.Sequence()),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(AppColumnID, e.AppID),
|
||||||
|
handler.NewCond(AppColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *appProjection) reduceAPIConfigSecretHashUpdated(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*project.APIConfigSecretHashUpdatedEvent)
|
||||||
|
if !ok {
|
||||||
|
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-ttb0I", "reduce.wrong.event.type %s", project.APIConfigSecretHashUpdatedType)
|
||||||
|
}
|
||||||
|
return handler.NewMultiStatement(
|
||||||
|
e,
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(AppAPIConfigColumnClientSecret, e.HashedSecret),
|
||||||
},
|
},
|
||||||
[]handler.Condition{
|
[]handler.Condition{
|
||||||
handler.NewCond(AppAPIConfigColumnAppID, e.AppID),
|
handler.NewCond(AppAPIConfigColumnAppID, e.AppID),
|
||||||
@ -449,7 +485,7 @@ func (p *appProjection) reduceOIDCConfigAdded(event eventstore.Event) (*handler.
|
|||||||
handler.NewCol(AppOIDCConfigColumnInstanceID, e.Aggregate().InstanceID),
|
handler.NewCol(AppOIDCConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
handler.NewCol(AppOIDCConfigColumnVersion, e.Version),
|
handler.NewCol(AppOIDCConfigColumnVersion, e.Version),
|
||||||
handler.NewCol(AppOIDCConfigColumnClientID, e.ClientID),
|
handler.NewCol(AppOIDCConfigColumnClientID, e.ClientID),
|
||||||
handler.NewCol(AppOIDCConfigColumnClientSecret, e.ClientSecret),
|
handler.NewCol(AppOIDCConfigColumnClientSecret, crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)),
|
||||||
handler.NewCol(AppOIDCConfigColumnRedirectUris, database.TextArray[string](e.RedirectUris)),
|
handler.NewCol(AppOIDCConfigColumnRedirectUris, database.TextArray[string](e.RedirectUris)),
|
||||||
handler.NewCol(AppOIDCConfigColumnResponseTypes, database.NumberArray[domain.OIDCResponseType](e.ResponseTypes)),
|
handler.NewCol(AppOIDCConfigColumnResponseTypes, database.NumberArray[domain.OIDCResponseType](e.ResponseTypes)),
|
||||||
handler.NewCol(AppOIDCConfigColumnGrantTypes, database.NumberArray[domain.OIDCGrantType](e.GrantTypes)),
|
handler.NewCol(AppOIDCConfigColumnGrantTypes, database.NumberArray[domain.OIDCGrantType](e.GrantTypes)),
|
||||||
@ -569,7 +605,37 @@ func (p *appProjection) reduceOIDCConfigSecretChanged(event eventstore.Event) (*
|
|||||||
e,
|
e,
|
||||||
handler.AddUpdateStatement(
|
handler.AddUpdateStatement(
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(AppOIDCConfigColumnClientSecret, e.ClientSecret),
|
handler.NewCol(AppOIDCConfigColumnClientSecret, crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(AppOIDCConfigColumnAppID, e.AppID),
|
||||||
|
handler.NewCond(AppOIDCConfigColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
handler.WithTableSuffix(appOIDCTableSuffix),
|
||||||
|
),
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(AppColumnChangeDate, e.CreationDate()),
|
||||||
|
handler.NewCol(AppColumnSequence, e.Sequence()),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(AppColumnID, e.AppID),
|
||||||
|
handler.NewCond(AppColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *appProjection) reduceOIDCConfigSecretHashUpdated(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*project.OIDCConfigSecretHashUpdatedEvent)
|
||||||
|
if !ok {
|
||||||
|
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-toSh1", "reduce.wrong.event.type %s", project.OIDCConfigSecretHashUpdatedType)
|
||||||
|
}
|
||||||
|
return handler.NewMultiStatement(
|
||||||
|
e,
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(AppOIDCConfigColumnClientSecret, e.HashedSecret),
|
||||||
},
|
},
|
||||||
[]handler.Condition{
|
[]handler.Condition{
|
||||||
handler.NewCond(AppOIDCConfigColumnAppID, e.AppID),
|
handler.NewCond(AppOIDCConfigColumnAppID, e.AppID),
|
||||||
|
@ -46,7 +46,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.apps6 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
expectedStmt: "INSERT INTO projections.apps7 (id, name, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"app-id",
|
"app-id",
|
||||||
"my-app",
|
"my-app",
|
||||||
@ -83,7 +83,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.apps7 SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"my-app",
|
"my-app",
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -136,7 +136,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.apps7 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
domain.AppStateInactive,
|
domain.AppStateInactive,
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -168,7 +168,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.apps7 SET (state, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
domain.AppStateActive,
|
domain.AppStateActive,
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -200,7 +200,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.apps6 WHERE (id = $1) AND (instance_id = $2)",
|
expectedStmt: "DELETE FROM projections.apps7 WHERE (id = $1) AND (instance_id = $2)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -227,7 +227,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.apps6 WHERE (project_id = $1) AND (instance_id = $2)",
|
expectedStmt: "DELETE FROM projections.apps7 WHERE (project_id = $1) AND (instance_id = $2)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -254,7 +254,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.apps6 WHERE (instance_id = $1)",
|
expectedStmt: "DELETE FROM projections.apps7 WHERE (instance_id = $1)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
},
|
},
|
||||||
@ -264,7 +264,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "project reduceAPIConfigAdded",
|
name: "project reduceAPIConfigAdded, v1 secret",
|
||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
@ -273,7 +273,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
[]byte(`{
|
[]byte(`{
|
||||||
"appId": "app-id",
|
"appId": "app-id",
|
||||||
"clientId": "client-id",
|
"clientId": "client-id",
|
||||||
"clientSecret": {},
|
"clientSecret": {"CryptoType":1,"Algorithm":"bcrypt","Crypted":"c2VjcmV0"},
|
||||||
"authMethodType": 1
|
"authMethodType": 1
|
||||||
}`),
|
}`),
|
||||||
), project.APIConfigAddedEventMapper),
|
), project.APIConfigAddedEventMapper),
|
||||||
@ -285,17 +285,61 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.apps6_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
|
expectedStmt: "INSERT INTO projections.apps7_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
"client-id",
|
"client-id",
|
||||||
anyArg{},
|
"secret",
|
||||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceAPIConfigAdded, v2 secret",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.APIConfigAddedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"appId": "app-id",
|
||||||
|
"clientId": "client-id",
|
||||||
|
"hashedSecret": "secret",
|
||||||
|
"authMethodType": 1
|
||||||
|
}`),
|
||||||
|
), project.APIConfigAddedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceAPIConfigAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO projections.apps7_api_configs (app_id, instance_id, client_id, client_secret, auth_method) VALUES ($1, $2, $3, $4, $5)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
"client-id",
|
||||||
|
"secret",
|
||||||
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -317,7 +361,6 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
[]byte(`{
|
[]byte(`{
|
||||||
"appId": "app-id",
|
"appId": "app-id",
|
||||||
"clientId": "client-id",
|
"clientId": "client-id",
|
||||||
"clientSecret": {},
|
|
||||||
"authMethodType": 1
|
"authMethodType": 1
|
||||||
}`),
|
}`),
|
||||||
), project.APIConfigChangedEventMapper),
|
), project.APIConfigChangedEventMapper),
|
||||||
@ -329,16 +372,15 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6_api_configs SET (client_secret, auth_method) = ($1, $2) WHERE (app_id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7_api_configs SET auth_method = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
|
||||||
domain.APIAuthMethodTypePrivateKeyJWT,
|
domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -372,7 +414,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "project reduceAPIConfigSecretChanged",
|
name: "project reduceAPIConfigSecretChanged, v1 secret",
|
||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
@ -380,7 +422,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
project.AggregateType,
|
project.AggregateType,
|
||||||
[]byte(`{
|
[]byte(`{
|
||||||
"appId": "app-id",
|
"appId": "app-id",
|
||||||
"client_secret": {}
|
"clientSecret": {"CryptoType":1,"Algorithm":"bcrypt","Crypted":"c2VjcmV0"}
|
||||||
}`),
|
}`),
|
||||||
), project.APIConfigSecretChangedEventMapper),
|
), project.APIConfigSecretChangedEventMapper),
|
||||||
},
|
},
|
||||||
@ -391,15 +433,15 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
expectedStmt: "UPDATE projections.apps7_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
"secret",
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -412,7 +454,87 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "project reduceOIDCConfigAdded",
|
name: "project reduceAPIConfigSecretChanged, v2 secret",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.APIConfigSecretChangedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"appId": "app-id",
|
||||||
|
"hashedSecret": "secret"
|
||||||
|
}`),
|
||||||
|
), project.APIConfigSecretChangedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceAPIConfigSecretChanged,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"secret",
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceAPIConfigSecretHashUpdated",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.APIConfigSecretHashUpdatedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"appId": "app-id",
|
||||||
|
"hashedSecret": "secret"
|
||||||
|
}`),
|
||||||
|
), eventstore.GenericEventMapper[project.APIConfigSecretHashUpdatedEvent]),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceAPIConfigSecretHashUpdated,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7_api_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"secret",
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceOIDCConfigAdded, v1 secret",
|
||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
@ -422,7 +544,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
"oidcVersion": 0,
|
"oidcVersion": 0,
|
||||||
"appId": "app-id",
|
"appId": "app-id",
|
||||||
"clientId": "client-id",
|
"clientId": "client-id",
|
||||||
"clientSecret": {},
|
"clientSecret": {"CryptoType":1,"Algorithm":"bcrypt","Crypted":"c2VjcmV0"},
|
||||||
"redirectUris": ["redirect.one.ch", "redirect.two.ch"],
|
"redirectUris": ["redirect.one.ch", "redirect.two.ch"],
|
||||||
"responseTypes": [1,2],
|
"responseTypes": [1,2],
|
||||||
"grantTypes": [1,2],
|
"grantTypes": [1,2],
|
||||||
@ -447,13 +569,13 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.apps6_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
|
expectedStmt: "INSERT INTO projections.apps7_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
"client-id",
|
"client-id",
|
||||||
anyArg{},
|
"secret",
|
||||||
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
|
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
|
||||||
database.NumberArray[domain.OIDCResponseType]{1, 2},
|
database.NumberArray[domain.OIDCResponseType]{1, 2},
|
||||||
database.NumberArray[domain.OIDCGrantType]{1, 2},
|
database.NumberArray[domain.OIDCGrantType]{1, 2},
|
||||||
@ -471,7 +593,79 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceOIDCConfigAdded, v2 secret",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.OIDCConfigAddedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"oidcVersion": 0,
|
||||||
|
"appId": "app-id",
|
||||||
|
"clientId": "client-id",
|
||||||
|
"hashedSecret": "secret",
|
||||||
|
"redirectUris": ["redirect.one.ch", "redirect.two.ch"],
|
||||||
|
"responseTypes": [1,2],
|
||||||
|
"grantTypes": [1,2],
|
||||||
|
"applicationType": 2,
|
||||||
|
"authMethodType": 2,
|
||||||
|
"postLogoutRedirectUris": ["logout.one.ch", "logout.two.ch"],
|
||||||
|
"devMode": true,
|
||||||
|
"accessTokenType": 1,
|
||||||
|
"accessTokenRoleAssertion": true,
|
||||||
|
"idTokenRoleAssertion": true,
|
||||||
|
"idTokenUserinfoAssertion": true,
|
||||||
|
"clockSkew": 1000,
|
||||||
|
"additionalOrigins": ["origin.one.ch", "origin.two.ch"],
|
||||||
|
"skipNativeAppSuccessPage": true
|
||||||
|
}`),
|
||||||
|
), project.OIDCConfigAddedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceOIDCConfigAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO projections.apps7_oidc_configs (app_id, instance_id, version, client_id, client_secret, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
domain.OIDCVersionV1,
|
||||||
|
"client-id",
|
||||||
|
"secret",
|
||||||
|
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
|
||||||
|
database.NumberArray[domain.OIDCResponseType]{1, 2},
|
||||||
|
database.NumberArray[domain.OIDCGrantType]{1, 2},
|
||||||
|
domain.OIDCApplicationTypeNative,
|
||||||
|
domain.OIDCAuthMethodTypeNone,
|
||||||
|
database.TextArray[string]{"logout.one.ch", "logout.two.ch"},
|
||||||
|
true,
|
||||||
|
domain.OIDCTokenTypeJWT,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
1 * time.Microsecond,
|
||||||
|
database.TextArray[string]{"origin.one.ch", "origin.two.ch"},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -518,7 +712,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) WHERE (app_id = $16) AND (instance_id = $17)",
|
expectedStmt: "UPDATE projections.apps7_oidc_configs SET (version, redirect_uris, response_types, grant_types, application_type, auth_method_type, post_logout_redirect_uris, is_dev_mode, access_token_type, access_token_role_assertion, id_token_role_assertion, id_token_userinfo_assertion, clock_skew, additional_origins, skip_native_app_success_page) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) WHERE (app_id = $16) AND (instance_id = $17)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
domain.OIDCVersionV1,
|
domain.OIDCVersionV1,
|
||||||
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
|
database.TextArray[string]{"redirect.one.ch", "redirect.two.ch"},
|
||||||
@ -540,7 +734,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -574,7 +768,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "project reduceOIDCConfigSecretChanged",
|
name: "project reduceOIDCConfigSecretChanged, v1 secret",
|
||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
@ -582,7 +776,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
project.AggregateType,
|
project.AggregateType,
|
||||||
[]byte(`{
|
[]byte(`{
|
||||||
"appId": "app-id",
|
"appId": "app-id",
|
||||||
"client_secret": {}
|
"clientSecret": {"CryptoType":1,"Algorithm":"bcrypt","Crypted":"c2VjcmV0"}
|
||||||
}`),
|
}`),
|
||||||
), project.OIDCConfigSecretChangedEventMapper),
|
), project.OIDCConfigSecretChangedEventMapper),
|
||||||
},
|
},
|
||||||
@ -593,15 +787,95 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
expectedStmt: "UPDATE projections.apps7_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
"secret",
|
||||||
"app-id",
|
"app-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.apps6 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceOIDCConfigSecretChanged, v2 secret",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.OIDCConfigSecretChangedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"appId": "app-id",
|
||||||
|
"hashedSecret": "secret"
|
||||||
|
}`),
|
||||||
|
), project.OIDCConfigSecretChangedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceOIDCConfigSecretChanged,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"secret",
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project reduceOIDCConfigSecretHashUpdated",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
project.OIDCConfigSecretHashUpdatedType,
|
||||||
|
project.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"appId": "app-id",
|
||||||
|
"hashedSecret": "secret"
|
||||||
|
}`),
|
||||||
|
), eventstore.GenericEventMapper[project.OIDCConfigSecretHashUpdatedEvent]),
|
||||||
|
},
|
||||||
|
reduce: (&appProjection{}).reduceOIDCConfigSecretHashUpdated,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("project"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7_oidc_configs SET client_secret = $1 WHERE (app_id = $2) AND (instance_id = $3)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"secret",
|
||||||
|
"app-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.apps7 SET (change_date, sequence) = ($1, $2) WHERE (id = $3) AND (instance_id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
@ -630,7 +904,7 @@ func TestAppProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.apps6 WHERE (instance_id = $1) AND (resource_owner = $2)",
|
expectedStmt: "DELETE FROM projections.apps7 WHERE (instance_id = $1) AND (resource_owner = $2)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"instance-id",
|
"instance-id",
|
||||||
"agg-id",
|
"agg-id",
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
|
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||||
@ -15,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UserTable = "projections.users11"
|
UserTable = "projections.users12"
|
||||||
UserHumanTable = UserTable + "_" + UserHumanSuffix
|
UserHumanTable = UserTable + "_" + UserHumanSuffix
|
||||||
UserMachineTable = UserTable + "_" + UserMachineSuffix
|
UserMachineTable = UserTable + "_" + UserMachineSuffix
|
||||||
UserNotifyTable = UserTable + "_" + UserNotifySuffix
|
UserNotifyTable = UserTable + "_" + UserNotifySuffix
|
||||||
@ -125,7 +126,7 @@ func (*userProjection) Init() *old_handler.Check {
|
|||||||
handler.NewColumn(MachineUserInstanceIDCol, handler.ColumnTypeText),
|
handler.NewColumn(MachineUserInstanceIDCol, handler.ColumnTypeText),
|
||||||
handler.NewColumn(MachineNameCol, handler.ColumnTypeText),
|
handler.NewColumn(MachineNameCol, handler.ColumnTypeText),
|
||||||
handler.NewColumn(MachineDescriptionCol, handler.ColumnTypeText, handler.Nullable()),
|
handler.NewColumn(MachineDescriptionCol, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(MachineSecretCol, handler.ColumnTypeJSONB, handler.Nullable()),
|
handler.NewColumn(MachineSecretCol, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(MachineAccessTokenTypeCol, handler.ColumnTypeEnum, handler.Default(0)),
|
handler.NewColumn(MachineAccessTokenTypeCol, handler.ColumnTypeEnum, handler.Default(0)),
|
||||||
},
|
},
|
||||||
handler.NewPrimaryKey(MachineUserInstanceIDCol, MachineUserIDCol),
|
handler.NewPrimaryKey(MachineUserInstanceIDCol, MachineUserIDCol),
|
||||||
@ -285,6 +286,10 @@ func (p *userProjection) Reducers() []handler.AggregateReducer {
|
|||||||
Event: user.MachineSecretSetType,
|
Event: user.MachineSecretSetType,
|
||||||
Reduce: p.reduceMachineSecretSet,
|
Reduce: p.reduceMachineSecretSet,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: user.MachineSecretHashUpdatedType,
|
||||||
|
Reduce: p.reduceMachineSecretHashUpdated,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: user.MachineSecretRemovedType,
|
Event: user.MachineSecretRemovedType,
|
||||||
Reduce: p.reduceMachineSecretRemoved,
|
Reduce: p.reduceMachineSecretRemoved,
|
||||||
@ -354,7 +359,7 @@ func (p *userProjection) reduceHumanAdded(event eventstore.Event) (*handler.Stat
|
|||||||
handler.NewCol(NotifyInstanceIDCol, e.Aggregate().InstanceID),
|
handler.NewCol(NotifyInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
handler.NewCol(NotifyLastEmailCol, e.EmailAddress),
|
handler.NewCol(NotifyLastEmailCol, e.EmailAddress),
|
||||||
handler.NewCol(NotifyLastPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
|
handler.NewCol(NotifyLastPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
|
||||||
handler.NewCol(NotifyPasswordSetCol, user.SecretOrEncodedHash(e.Secret, e.EncodedHash) != ""),
|
handler.NewCol(NotifyPasswordSetCol, crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash) != ""),
|
||||||
},
|
},
|
||||||
handler.WithTableSuffix(UserNotifySuffix),
|
handler.WithTableSuffix(UserNotifySuffix),
|
||||||
),
|
),
|
||||||
@ -403,7 +408,7 @@ func (p *userProjection) reduceHumanRegistered(event eventstore.Event) (*handler
|
|||||||
handler.NewCol(NotifyInstanceIDCol, e.Aggregate().InstanceID),
|
handler.NewCol(NotifyInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
handler.NewCol(NotifyLastEmailCol, e.EmailAddress),
|
handler.NewCol(NotifyLastEmailCol, e.EmailAddress),
|
||||||
handler.NewCol(NotifyLastPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
|
handler.NewCol(NotifyLastPhoneCol, &sql.NullString{String: string(e.PhoneNumber), Valid: e.PhoneNumber != ""}),
|
||||||
handler.NewCol(NotifyPasswordSetCol, user.SecretOrEncodedHash(e.Secret, e.EncodedHash) != ""),
|
handler.NewCol(NotifyPasswordSetCol, crypto.SecretOrEncodedHash(e.Secret, e.EncodedHash) != ""),
|
||||||
},
|
},
|
||||||
handler.WithTableSuffix(UserNotifySuffix),
|
handler.WithTableSuffix(UserNotifySuffix),
|
||||||
),
|
),
|
||||||
@ -952,7 +957,37 @@ func (p *userProjection) reduceMachineSecretSet(event eventstore.Event) (*handle
|
|||||||
),
|
),
|
||||||
handler.AddUpdateStatement(
|
handler.AddUpdateStatement(
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(MachineSecretCol, e.ClientSecret),
|
handler.NewCol(MachineSecretCol, crypto.SecretOrEncodedHash(e.ClientSecret, e.HashedSecret)),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(MachineUserIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCond(MachineUserInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
handler.WithTableSuffix(UserMachineSuffix),
|
||||||
|
),
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *userProjection) reduceMachineSecretHashUpdated(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*user.MachineSecretHashUpdatedEvent)
|
||||||
|
if !ok {
|
||||||
|
return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-Wieng4u", "reduce.wrong.event.type %s", user.MachineSecretHashUpdatedType)
|
||||||
|
}
|
||||||
|
return handler.NewMultiStatement(
|
||||||
|
e,
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(UserChangeDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(UserSequenceCol, e.Sequence()),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(UserIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCond(UserInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(MachineSecretCol, e.HashedSecret),
|
||||||
},
|
},
|
||||||
[]handler.Condition{
|
[]handler.Condition{
|
||||||
handler.NewCond(MachineUserIDCol, e.Aggregate().ID),
|
handler.NewCond(MachineUserIDCol, e.Aggregate().ID),
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user