feat: application commands (#50)

* feat: eventstore repository

* fix: remove gorm

* version

* feat: pkg

* feat: add some files for project

* feat: eventstore without eventstore-lib

* rename files

* gnueg

* fix: key json

* fix: add object

* fix: change imports

* fix: internal models

* fix: some imports

* fix: global model

* feat: add global view functions

* fix: add some functions on repo

* feat(eventstore): sdk

* fix(eventstore): search query

* fix(eventstore): rename app to eventstore

* delete empty test

* remove unused func

* merge master

* fix(eventstore): tests

* fix(models): delete unused struct

* fix: some funcitons

* feat(eventstore): implemented push events

* fix: move project eventstore to project package

* fix: change project eventstore funcs

* feat(eventstore): overwrite context data

* fix: change project eventstore

* fix: add project repo to mgmt server

* feat(types): SQL-config

* fix: commented code

* feat(eventstore): options to overwrite editor

* feat: auth interceptor and cockroach migrations

* fix: migrations

* fix: fix filter

* fix: not found on getbyid

* fix: use global sql config

* fix: add sequence

* fix: add some tests

* fix(eventstore): nullable sequence

* fix: add some tests

* merge

* fix: add some tests

* fix(migrations): correct statements for sequence

* fix: add some tests

* fix: add some tests

* fix: changes from mr

* fix: changes from mr

* fix: add some tests

* Update internal/eventstore/models/field.go

Co-Authored-By: livio-a <livio.a@gmail.com>

* fix(eventstore): code quality

* fix: add types to aggregate/Event-types

* fix: try tests

* fix(eventstore): rename modifier* to editor*

* fix(eventstore): delete editor_org

* fix(migrations): remove editor_org field,
rename modifier_* to editor_*

* fix: query tests

* fix: use prepare funcs

* fix: go mod

* fix: generate files

* fix(eventstore): tests

* fix(eventstore): rename modifier to editor

* fix(migrations): add cluster migration,
fix(migrations): fix typo of host in clean clsuter

* fix(eventstore): move health

* fix(eventstore): AggregateTypeFilter aggregateType as param

* code quality

* fix: go tests

* feat: add member funcs

* feat: add member model

* feat: add member events

* feat: add member repo model

* fix: better error func testing

* fix: project member funcs

* fix: add tests

* fix: add tests

* feat: implement member requests

* fix: merge master

* fix: merge master

* fix: read existing in project repo

* fix: fix tests

* feat: add internal cache

* feat: add cache mock

* fix: return values of cache mock

* feat: add project role

* fix: add cache config

* fix: add role to eventstore

* fix: use eventstore sdk

* fix: use eventstore sdk

* fix: add project role grpc requests

* fix: fix getby id

* fix: changes for mr

* fix: change value to interface

* feat: add app event creations

* fix: searchmethods

* Update internal/project/model/project_member.go

Co-Authored-By: Silvan <silvan.reusser@gmail.com>

* fix: use get project func

* fix: append events

* fix: check if value is string on equal ignore case

* fix: add changes test

* fix: add go mod

* fix: add some tests

* fix: return err not nil

* fix: return err not nil

* fix: add aggregate funcs and tests

* fix: add oidc aggregate funcs and tests

* fix: add oidc

* fix: add some tests

* fix: tests

* fix: oidc validation

* fix: generate client secret

* fix: generate client id

* fix: test change app

* fix: deactivate/reactivate application

* fix: change oidc config

* fix: change oidc config secret

* fix: implement grpc app funcs

* fix: add application requests

* fix: converter

* fix: converter

* fix: converter and generate clientid

* fix: tests

* fix: some fixes

* feat: mr changes

* fix: remove state converted

* fix: add default oidc config

* fix: use crypto pw generator

* fix: rename responsetype

* create GeneratorConfig and refactor some crypto.Generator code (#70)

* Update internal/project/model/project_role.go

Co-Authored-By: Silvan <silvan.reusser@gmail.com>

* fix: change objectroot id

* fix: caos err id

Co-authored-by: adlerhurst <silvan.reusser@gmail.com>
Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
Fabi 2020-04-21 17:00:32 +02:00 committed by GitHub
parent 802bb56ea1
commit 04b4cd80b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 7857 additions and 2951 deletions

View File

@ -31,6 +31,14 @@ Mgmt:
Type: 'fastcache'
Config:
MaxCacheSizeInByte: 10485760 #10mb
PasswordSaltCost: 14
ClientSecretGenerator:
Length: 64
IncludeLowerLetters: true
IncludeUpperLetters: true
IncludeDigits: true
IncludeSymbols: true
Auth:
API:

1
go.mod
View File

@ -34,6 +34,7 @@ require (
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.0.3
github.com/rs/cors v1.7.0
github.com/sethvargo/go-password v0.1.3
github.com/sirupsen/logrus v1.5.0 // indirect
github.com/sony/sonyflake v1.0.0
github.com/stretchr/testify v1.5.1

2
go.sum
View File

@ -254,6 +254,8 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sethvargo/go-password v0.1.3 h1:18KkbGDkw8SuzeohAbWqBLNSfRQblVwEHOLbPa0PvWM=
github.com/sethvargo/go-password v0.1.3/go.mod h1:2tyaaoHK/AlXwh5WWQDYjqQbHcq4cjPj5qb/ciYvu/Q=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=

View File

@ -4,16 +4,26 @@ import (
"crypto/rand"
"time"
"github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/errors"
)
var (
LowerLetters = []rune("abcdefghijklmnopqrstuvwxyz")
UpperLetters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Digits = []rune("0123456789")
Symbols = []rune("~!@#$^&*()_+`-={}|[]:<>?,./")
lowerLetters = []rune("abcdefghijklmnopqrstuvwxyz")
upperLetters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
digits = []rune("0123456789")
symbols = []rune("~!@#$^&*()_+`-={}|[]:<>?,./")
)
type GeneratorConfig struct {
Length uint
Expiry types.Duration
IncludeLowerLetters bool
IncludeUpperLetters bool
IncludeDigits bool
IncludeSymbols bool
}
type Generator interface {
Length() uint
Expiry() time.Duration
@ -21,66 +31,73 @@ type Generator interface {
Runes() []rune
}
type EncryptionGenerator struct {
type generator struct {
length uint
expiry time.Duration
alg EncryptionAlgorithm
runes []rune
}
func (g *EncryptionGenerator) Length() uint {
func (g *generator) Length() uint {
return g.length
}
func (g *EncryptionGenerator) Expiry() time.Duration {
func (g *generator) Expiry() time.Duration {
return g.expiry
}
func (g *EncryptionGenerator) Alg() Crypto {
return g.alg
}
func (g *EncryptionGenerator) Runes() []rune {
func (g *generator) Runes() []rune {
return g.runes
}
func NewEncryptionGenerator(length uint, expiry time.Duration, alg EncryptionAlgorithm, runes []rune) *EncryptionGenerator {
return &EncryptionGenerator{
length: length,
expiry: expiry,
alg: alg,
runes: runes,
type encryptionGenerator struct {
generator
alg EncryptionAlgorithm
}
func (g *encryptionGenerator) Alg() Crypto {
return g.alg
}
func NewEncryptionGenerator(config GeneratorConfig, algorithm EncryptionAlgorithm) Generator {
return &encryptionGenerator{
newGenerator(config),
algorithm,
}
}
type HashGenerator struct {
length uint
expiry time.Duration
alg HashAlgorithm
runes []rune
type hashGenerator struct {
generator
alg HashAlgorithm
}
func (g *HashGenerator) Length() uint {
return g.length
}
func (g *HashGenerator) Expiry() time.Duration {
return g.expiry
}
func (g *HashGenerator) Alg() Crypto {
func (g *hashGenerator) Alg() Crypto {
return g.alg
}
func (g *HashGenerator) Runes() []rune {
return g.runes
func NewHashGenerator(config GeneratorConfig, algorithm HashAlgorithm) Generator {
return &hashGenerator{
newGenerator(config),
algorithm,
}
}
func NewHashGenerator(length uint, expiry time.Duration, alg HashAlgorithm, runes []rune) *HashGenerator {
return &HashGenerator{
length: length,
expiry: expiry,
alg: alg,
func newGenerator(config GeneratorConfig) generator {
var runes []rune
if config.IncludeLowerLetters {
runes = append(runes, lowerLetters...)
}
if config.IncludeUpperLetters {
runes = append(runes, upperLetters...)
}
if config.IncludeDigits {
runes = append(runes, digits...)
}
if config.IncludeSymbols {
runes = append(runes, symbols...)
}
return generator{
length: config.Length,
expiry: config.Expiry.Duration,
runes: runes,
}
}
@ -98,6 +115,9 @@ func NewCode(g Generator) (*CryptoValue, string, error) {
}
func IsCodeExpired(creationDate time.Time, expiry time.Duration) bool {
if expiry == 0 {
return false
}
return creationDate.Add(expiry).Before(time.Now().UTC())
}

View File

@ -79,6 +79,14 @@ func TestIsCodeExpired(t *testing.T) {
},
false,
},
{
"never expires",
args{
creationDate: time.Now().Add(-5 * time.Minute),
expiry: 0,
},
false,
},
{
"expired",
args{

View File

@ -5,15 +5,15 @@ import (
)
type ObjectRoot struct {
ID string `json:"-"`
AggregateID string `json:"-"`
Sequence uint64 `json:"-"`
CreationDate time.Time `json:"-"`
ChangeDate time.Time `json:"-"`
}
func (o *ObjectRoot) AppendEvent(event *Event) {
if o.ID == "" {
o.ID = event.AggregateID
if o.AggregateID == "" {
o.AggregateID = event.AggregateID
}
o.ChangeDate = event.CreationDate

View File

@ -55,7 +55,7 @@ func TestObjectRoot_AppendEvent(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &ObjectRoot{
ID: tt.fields.ID,
AggregateID: tt.fields.ID,
Sequence: tt.fields.Sequence,
CreationDate: tt.fields.CreationDate,
ChangeDate: tt.fields.ChangeDate,

View File

@ -50,3 +50,49 @@ func (repo *ProjectRepo) RemoveProjectMember(ctx context.Context, projectID, use
member := proj_model.NewProjectMember(projectID, userID)
return repo.ProjectEvents.RemoveProjectMember(ctx, member)
}
func (repo *ProjectRepo) AddProjectRole(ctx context.Context, member *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
return repo.ProjectEvents.AddProjectRole(ctx, member)
}
func (repo *ProjectRepo) ChangeProjectRole(ctx context.Context, member *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
return repo.ProjectEvents.ChangeProjectRole(ctx, member)
}
func (repo *ProjectRepo) RemoveProjectRole(ctx context.Context, projectID, key string) error {
member := proj_model.NewProjectRole(projectID, key)
return repo.ProjectEvents.RemoveProjectRole(ctx, member)
}
func (repo *ProjectRepo) ApplicationByID(ctx context.Context, projectID, appID string) (app *proj_model.Application, err error) {
return repo.ProjectEvents.ApplicationByIDs(ctx, projectID, appID)
}
func (repo *ProjectRepo) AddApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) {
return repo.ProjectEvents.AddApplication(ctx, app)
}
func (repo *ProjectRepo) ChangeApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) {
return repo.ProjectEvents.ChangeApplication(ctx, app)
}
func (repo *ProjectRepo) DeactivateApplication(ctx context.Context, projectID, appID string) (*proj_model.Application, error) {
return repo.ProjectEvents.DeactivateApplication(ctx, projectID, appID)
}
func (repo *ProjectRepo) ReactivateApplication(ctx context.Context, projectID, appID string) (*proj_model.Application, error) {
return repo.ProjectEvents.ReactivateApplication(ctx, projectID, appID)
}
func (repo *ProjectRepo) RemoveApplication(ctx context.Context, projectID, appID string) error {
app := proj_model.NewApplication(projectID, appID)
return repo.ProjectEvents.RemoveApplication(ctx, app)
}
func (repo *ProjectRepo) ChangeOIDCConfig(ctx context.Context, config *proj_model.OIDCConfig) (*proj_model.OIDCConfig, error) {
return repo.ProjectEvents.ChangeOIDCConfig(ctx, config)
}
func (repo *ProjectRepo) ChangeOIDConfigSecret(ctx context.Context, projectID, appID string) (*proj_model.OIDCConfig, error) {
return repo.ProjectEvents.ChangeOIDCConfigSecret(ctx, projectID, appID)
}

View File

@ -2,6 +2,8 @@ package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/crypto"
es_int "github.com/caos/zitadel/internal/eventstore"
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
)
@ -10,6 +12,8 @@ type Config struct {
Eventstore es_int.Config
//View view.ViewConfig
//Spooler spooler.SpoolerConfig
PasswordSaltCost int
ClientSecretGenerator crypto.GeneratorConfig
}
type EsRepository struct {
@ -33,7 +37,12 @@ func Start(conf Config) (*EsRepository, error) {
//conf.Spooler.SQL = sql
//spool := spooler.StartSpooler(conf.Spooler)
project, err := es_proj.StartProject(es_proj.ProjectConfig{Eventstore: es, Cache: conf.Eventstore.Cache})
project, err := es_proj.StartProject(es_proj.ProjectConfig{
Eventstore: es,
Cache: conf.Eventstore.Cache,
PasswordSaltCost: conf.PasswordSaltCost,
ClientSecretGenerator: conf.ClientSecretGenerator,
})
if err != nil {
return nil, err
}

View File

@ -16,4 +16,17 @@ type ProjectRepository interface {
AddProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
ChangeProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
RemoveProjectMember(ctx context.Context, projectID, userID string) error
AddProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
ChangeProjectRole(ctx context.Context, role *model.ProjectRole) (*model.ProjectRole, error)
RemoveProjectRole(ctx context.Context, projectID, key string) error
ApplicationByID(ctx context.Context, projectID, appID string) (*model.Application, error)
AddApplication(ctx context.Context, app *model.Application) (*model.Application, error)
ChangeApplication(ctx context.Context, app *model.Application) (*model.Application, error)
DeactivateApplication(ctx context.Context, projectID, appID string) (*model.Application, error)
ReactivateApplication(ctx context.Context, projectID, appID string) (*model.Application, error)
RemoveApplication(ctx context.Context, projectID, appID string) error
ChangeOIDCConfig(ctx context.Context, config *model.OIDCConfig) (*model.OIDCConfig, error)
ChangeOIDConfigSecret(ctx context.Context, projectID, appID string) (*model.OIDCConfig, error)
}

View File

@ -0,0 +1,47 @@
package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type Application struct {
es_models.ObjectRoot
AppID string
State AppState
Name string
Type AppType
OIDCConfig *OIDCConfig
}
type AppState int32
const (
APPSTATE_ACTIVE AppState = iota
APPSTATE_INACTIVE
)
type AppType int32
const (
APPTYPE_UNDEFINED AppType = iota
APPTYPE_OIDC
APPTYPE_SAML
)
func NewApplication(projectID, appID string) *Application {
return &Application{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, AppID: appID, State: APPSTATE_ACTIVE}
}
func (a *Application) IsValid(includeConfig bool) bool {
if a.Name == "" || a.AggregateID == "" {
return false
}
if !includeConfig {
return true
}
if a.Type == APPTYPE_OIDC && !a.OIDCConfig.IsValid() {
return false
}
return true
}

View File

@ -0,0 +1,170 @@
package model
import (
"github.com/caos/zitadel/internal/eventstore/models"
"testing"
)
func TestApplicationValid(t *testing.T) {
type args struct {
app *Application
}
tests := []struct {
name string
args args
result bool
}{
{
name: "valid oidc application: responsetype code",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_CODE},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE},
},
},
},
result: true,
},
{
name: "invalid oidc application: responsetype code",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_CODE},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: false,
},
{
name: "valid oidc application: responsetype id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_ID_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: true,
},
{
name: "invalid oidc application: responsetype id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_ID_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE},
},
},
},
result: false,
},
{
name: "valid oidc application: responsetype token_id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: true,
},
{
name: "invalid oidc application: responsetype token_id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE},
},
},
},
result: false,
},
{
name: "valid oidc application: responsetype code & id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_CODE, OIDCRESPONSETYPE_ID_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: true,
},
{
name: "valid oidc application: responsetype code & token_id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_CODE, OIDCRESPONSETYPE_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: true,
},
{
name: "valid oidc application: responsetype code & id_token & token_id_token",
args: args{
app: &Application{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
AppID: "AppID",
Name: "Name",
Type: APPTYPE_OIDC,
OIDCConfig: &OIDCConfig{
ResponseTypes: []OIDCResponseType{OIDCRESPONSETYPE_CODE, OIDCRESPONSETYPE_ID_TOKEN, OIDCRESPONSETYPE_TOKEN},
GrantTypes: []OIDCGrantType{OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGRANTTYPE_IMPLICIT},
},
},
},
result: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.args.app.IsValid(true)
if result != tt.result {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, result)
}
})
}
}

View File

@ -0,0 +1,88 @@
package model
import (
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type OIDCConfig struct {
es_models.ObjectRoot
AppID string
ClientID string
ClientSecret *crypto.CryptoValue
ClientSecretString string
RedirectUris []string
ResponseTypes []OIDCResponseType
GrantTypes []OIDCGrantType
ApplicationType OIDCApplicationType
AuthMethodType OIDCAuthMethodType
PostLogoutRedirectUris []string
}
type OIDCResponseType int32
const (
OIDCRESPONSETYPE_CODE OIDCResponseType = iota
OIDCRESPONSETYPE_ID_TOKEN
OIDCRESPONSETYPE_TOKEN
)
type OIDCGrantType int32
const (
OIDCGRANTTYPE_AUTHORIZATION_CODE OIDCGrantType = iota
OIDCGRANTTYPE_IMPLICIT
OIDCGRANTTYPE_REFRESH_TOKEN
)
type OIDCApplicationType int32
const (
OIDCAPPLICATIONTYPE_WEB OIDCApplicationType = iota
OIDCAPPLICATIONTYPE_USER_AGENT
OIDCAPPLICATIONTYPE_NATIVE
)
type OIDCAuthMethodType int32
const (
OIDCAUTHMETHODTYPE_BASIC OIDCAuthMethodType = iota
OIDCAUTHMETHODTYPE_POST
OIDCAUTHMETHODTYPE_NONE
)
func (c *OIDCConfig) IsValid() bool {
grantTypes := c.getRequiredGrantTypes()
for _, grantType := range grantTypes {
ok := c.containsGrantType(grantType)
if !ok {
return false
}
}
return true
}
func (c *OIDCConfig) getRequiredGrantTypes() []OIDCGrantType {
grantTypes := make([]OIDCGrantType, 0)
implicit := false
for _, r := range c.ResponseTypes {
switch r {
case OIDCRESPONSETYPE_CODE:
grantTypes = append(grantTypes, OIDCGRANTTYPE_AUTHORIZATION_CODE)
case OIDCRESPONSETYPE_ID_TOKEN, OIDCRESPONSETYPE_TOKEN:
if !implicit {
grantTypes = append(grantTypes, OIDCGRANTTYPE_IMPLICIT)
}
}
}
return grantTypes
}
func (c *OIDCConfig) containsGrantType(grantType OIDCGrantType) bool {
for _, t := range c.GrantTypes {
if t == grantType {
return true
}
}
return false
}

View File

@ -2,37 +2,35 @@ package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
in_model "github.com/caos/zitadel/internal/model"
)
type Project struct {
es_models.ObjectRoot
State ProjectState
Name string
Members []*ProjectMember
State ProjectState
Name string
Members []*ProjectMember
Roles []*ProjectRole
Applications []*Application
}
type ProjectState in_model.Enum
type ProjectState int32
var states = []string{"Active", "Inactive"}
const (
PROJECTSTATE_ACTIVE ProjectState = iota
PROJECTSTATE_INACTIVE
)
func NewProject(id string) *Project {
return &Project{ObjectRoot: es_models.ObjectRoot{ID: id}, State: Active}
return &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: id}, State: PROJECTSTATE_ACTIVE}
}
func (p *Project) IsActive() bool {
if p.State == Active {
return true
}
return false
return p.State == PROJECTSTATE_ACTIVE
}
func (p *Project) IsValid() bool {
if p.Name == "" {
return false
}
return true
return p.Name != ""
}
func (p *Project) ContainsMember(member *ProjectMember) bool {
@ -43,3 +41,21 @@ func (p *Project) ContainsMember(member *ProjectMember) bool {
}
return false
}
func (p *Project) ContainsRole(role *ProjectRole) bool {
for _, r := range p.Roles {
if r.Key == role.Key {
return true
}
}
return false
}
func (p *Project) ContainsApp(app *Application) (*Application, bool) {
for _, a := range p.Applications {
if a.AppID == app.AppID {
return a, true
}
}
return nil, false
}

View File

@ -10,9 +10,9 @@ type ProjectMember struct {
}
func NewProjectMember(projectID, userID string) *ProjectMember {
return &ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: projectID}, UserID: userID}
return &ProjectMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, UserID: userID}
}
func (p *ProjectMember) IsValid() bool {
return p.ID != "" && p.UserID != "" && len(p.Roles) != 0
return p.AggregateID != "" && p.UserID != "" && len(p.Roles) != 0
}

View File

@ -0,0 +1,19 @@
package model
import es_models "github.com/caos/zitadel/internal/eventstore/models"
type ProjectRole struct {
es_models.ObjectRoot
Key string
DisplayName string
Group string
}
func NewProjectRole(projectID, key string) *ProjectRole {
return &ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, Key: key}
}
func (p *ProjectRole) IsValid() bool {
return p.AggregateID != "" && p.Key != ""
}

View File

@ -1,23 +0,0 @@
package model
type state int32
func (s state) String() string {
return states[s]
}
const (
Active state = iota
Inactive
)
func ProjectStateToInt(s ProjectState) int32 {
if s == nil {
return 0
}
return int32(s.(state))
}
func ProjectStateFromInt(index int32) ProjectState {
return state(index)
}

View File

@ -15,6 +15,7 @@ const (
ProjectMemberRemoved models.EventType = "project.member.removed"
ProjectRoleAdded models.EventType = "project.role.added"
ProjectRoleChanged models.EventType = "project.role.changed"
ProjectRoleRemoved models.EventType = "project.role.removed"
ProjectGrantAdded models.EventType = "project.grant.added"
@ -28,6 +29,7 @@ const (
ApplicationAdded models.EventType = "project.application.added"
ApplicationChanged models.EventType = "project.application.changed"
ApplicationRemoved models.EventType = "project.application.removed"
ApplicationDeactivated models.EventType = "project.application.deactivated"
ApplicationReactivated models.EventType = "project.application.reactivated"

View File

@ -19,7 +19,7 @@ func StartCache(conf *config.CacheConfig) (*ProjectCache, error) {
}
func (c *ProjectCache) getProject(ID string) (project *Project) {
project = &Project{ObjectRoot: models.ObjectRoot{ID: ID}}
project = &Project{ObjectRoot: models.ObjectRoot{AggregateID: ID}}
if err := c.projectCache.Get(ID, project); err != nil {
logging.Log("EVENT-4eTZh").WithError(err).Debug("error in getting cache")
}
@ -27,7 +27,7 @@ func (c *ProjectCache) getProject(ID string) (project *Project) {
}
func (c *ProjectCache) cacheProject(project *Project) {
err := c.projectCache.Set(project.ID, project)
err := c.projectCache.Set(project.AggregateID, project)
if err != nil {
logging.Log("EVENT-ThnBb").WithError(err).Debug("error in setting project cache")
}

View File

@ -2,7 +2,12 @@ package eventsourcing
import (
"context"
"strconv"
"github.com/sony/sonyflake"
"github.com/caos/zitadel/internal/cache/config"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
@ -12,11 +17,15 @@ import (
type ProjectEventstore struct {
es_int.Eventstore
projectCache *ProjectCache
pwGenerator crypto.Generator
idGenerator *sonyflake.Sonyflake
}
type ProjectConfig struct {
es_int.Eventstore
Cache *config.CacheConfig
Cache *config.CacheConfig
PasswordSaltCost int
ClientSecretGenerator crypto.GeneratorConfig
}
func StartProject(conf ProjectConfig) (*ProjectEventstore, error) {
@ -24,21 +33,26 @@ func StartProject(conf ProjectConfig) (*ProjectEventstore, error) {
if err != nil {
return nil, err
}
passwordAlg := crypto.NewBCrypt(conf.PasswordSaltCost)
pwGenerator := crypto.NewHashGenerator(conf.ClientSecretGenerator, passwordAlg)
idGenerator := sonyflake.NewSonyflake(sonyflake.Settings{})
return &ProjectEventstore{
Eventstore: conf.Eventstore,
projectCache: projectCache,
pwGenerator: pwGenerator,
idGenerator: idGenerator,
}, nil
}
func (es *ProjectEventstore) ProjectByID(ctx context.Context, id string) (*proj_model.Project, error) {
project := es.projectCache.getProject(id)
query, err := ProjectByIDQuery(project.ID, project.Sequence)
query, err := ProjectByIDQuery(project.AggregateID, project.Sequence)
if err != nil {
return nil, err
}
err = es_sdk.Filter(ctx, es.FilterEvents, project.AppendEvents, query)
if err != nil {
if err != nil && !(caos_errs.IsNotFound(err) && project.Sequence != 0) {
return nil, err
}
es.projectCache.cacheProject(project)
@ -49,11 +63,16 @@ func (es *ProjectEventstore) CreateProject(ctx context.Context, project *proj_mo
if !project.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
}
project.State = proj_model.Active
id, err := es.idGenerator.NextID()
if err != nil {
return nil, err
}
project.AggregateID = strconv.FormatUint(id, 10)
project.State = proj_model.PROJECTSTATE_ACTIVE
repoProject := ProjectFromModel(project)
createAggregate := ProjectCreateAggregate(es.AggregateCreator(), repoProject)
err := es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, createAggregate)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, createAggregate)
if err != nil {
return nil, err
}
@ -66,7 +85,7 @@ func (es *ProjectEventstore) UpdateProject(ctx context.Context, project *proj_mo
if !project.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
}
existingProject, err := es.ProjectByID(ctx, project.ID)
existingProject, err := es.ProjectByID(ctx, project.AggregateID)
if err != nil {
return nil, err
}
@ -121,7 +140,7 @@ func (es *ProjectEventstore) ProjectMemberByIDs(ctx context.Context, member *pro
if member.UserID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld93d", "userID missing")
}
project, err := es.ProjectByID(ctx, member.ID)
project, err := es.ProjectByID(ctx, member.AggregateID)
if err != nil {
return nil, err
}
@ -137,7 +156,7 @@ func (es *ProjectEventstore) AddProjectMember(ctx context.Context, member *proj_
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
}
existing, err := es.ProjectByID(ctx, member.ID)
existing, err := es.ProjectByID(ctx, member.AggregateID)
if err != nil {
return nil, err
}
@ -165,7 +184,7 @@ func (es *ProjectEventstore) ChangeProjectMember(ctx context.Context, member *pr
if !member.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
}
existing, err := es.ProjectByID(ctx, member.ID)
existing, err := es.ProjectByID(ctx, member.AggregateID)
if err != nil {
return nil, err
}
@ -190,7 +209,7 @@ func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *pr
if member.UserID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-d43fs", "UserID and Roles are required")
}
existing, err := es.ProjectByID(ctx, member.ID)
existing, err := es.ProjectByID(ctx, member.AggregateID)
if err != nil {
return err
}
@ -205,3 +224,307 @@ func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *pr
es.projectCache.cacheProject(repoProject)
return err
}
func (es *ProjectEventstore) AddProjectRole(ctx context.Context, role *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
if !role.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-idue3", "Key is required")
}
existing, err := es.ProjectByID(ctx, role.AggregateID)
if err != nil {
return nil, err
}
if existing.ContainsRole(role) {
return nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-sk35t", "Project contains role with same key")
}
repoProject := ProjectFromModel(existing)
repoRole := ProjectRoleFromModel(role)
projectAggregate := ProjectRoleAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRole)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
for _, r := range repoProject.Roles {
if r.Key == role.Key {
return ProjectRoleToModel(r), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-sie83", "Could not find role in list")
}
func (es *ProjectEventstore) ChangeProjectRole(ctx context.Context, role *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
if !role.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9die3", "Key is required")
}
existing, err := es.ProjectByID(ctx, role.AggregateID)
if err != nil {
return nil, err
}
if !existing.ContainsRole(role) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die34", "Role doesn't exist on this project")
}
repoProject := ProjectFromModel(existing)
repoRole := ProjectRoleFromModel(role)
projectAggregate := ProjectRoleChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRole)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
for _, r := range repoProject.Roles {
if r.Key == role.Key {
return ProjectRoleToModel(r), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-sl1or", "Could not find role in list")
}
func (es *ProjectEventstore) RemoveProjectRole(ctx context.Context, role *proj_model.ProjectRole) error {
if role.Key == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-id823", "Key is required")
}
existing, err := es.ProjectByID(ctx, role.AggregateID)
if err != nil {
return err
}
if !existing.ContainsRole(role) {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-oe823", "Role doesn't exist on project")
}
repoProject := ProjectFromModel(existing)
repoRole := ProjectRoleFromModel(role)
projectAggregate := ProjectRoleRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRole)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return err
}
es.projectCache.cacheProject(repoProject)
return nil
}
func (es *ProjectEventstore) ApplicationByIDs(ctx context.Context, projectID, appID string) (*proj_model.Application, error) {
if projectID == "" || appID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld93d", "project oder app AggregateID missing")
}
project, err := es.ProjectByID(ctx, projectID)
if err != nil {
return nil, err
}
for _, a := range project.Applications {
if a.AppID == appID {
return a, nil
}
}
return nil, caos_errs.ThrowNotFound(nil, "EVENT-8ei2s", "Could not find app")
}
func (es *ProjectEventstore) AddApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) {
if app == nil || !app.IsValid(true) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9eidw", "Some required fields are missing")
}
existing, err := es.ProjectByID(ctx, app.AggregateID)
if err != nil {
return nil, err
}
id, err := es.idGenerator.NextID()
if err != nil {
return nil, err
}
app.AppID = strconv.FormatUint(id, 10)
var stringPw string
var cryptoPw *crypto.CryptoValue
if app.OIDCConfig != nil {
app.OIDCConfig.AppID = strconv.FormatUint(id, 10)
stringPw, cryptoPw, err = generateNewClientSecret(es.pwGenerator)
if err != nil {
return nil, err
}
app.OIDCConfig.ClientSecret = cryptoPw
clientID, err := generateNewClientID(es.idGenerator, existing)
if err != nil {
return nil, err
}
app.OIDCConfig.ClientID = clientID
}
repoProject := ProjectFromModel(existing)
repoApp := AppFromModel(app)
addAggregate := ApplicationAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
converted := AppToModel(a)
converted.OIDCConfig.ClientSecretString = stringPw
return converted, nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-3udjs", "Could not find member in list")
}
func (es *ProjectEventstore) ChangeApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) {
if app == nil || !app.IsValid(false) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-dieuw", "some required fields missing")
}
existing, err := es.ProjectByID(ctx, app.AggregateID)
if err != nil {
return nil, err
}
if _, ok := existing.ContainsApp(app); !ok {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die83", "App is not in this project")
}
repoProject := ProjectFromModel(existing)
repoApp := AppFromModel(app)
projectAggregate := ApplicationChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
return AppToModel(a), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-dksi8", "Could not find app in list")
}
func (es *ProjectEventstore) RemoveApplication(ctx context.Context, app *proj_model.Application) error {
if app.AppID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-id832", "AppID is required")
}
existing, err := es.ProjectByID(ctx, app.AggregateID)
if err != nil {
return err
}
if _, ok := existing.ContainsApp(app); !ok {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-di83s", "Application doesn't exist on project")
}
repoProject := ProjectFromModel(existing)
appRepo := AppFromModel(app)
projectAggregate := ApplicationRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, appRepo)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return err
}
es.projectCache.cacheProject(repoProject)
return nil
}
func (es *ProjectEventstore) DeactivateApplication(ctx context.Context, projectID, appID string) (*proj_model.Application, error) {
if appID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-dlp9e", "appID missing")
}
existing, err := es.ProjectByID(ctx, projectID)
if err != nil {
return nil, err
}
app := &proj_model.Application{AppID: appID}
if _, ok := existing.ContainsApp(app); !ok {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-slpe9", "App is not in this project")
}
repoProject := ProjectFromModel(existing)
repoApp := AppFromModel(app)
projectAggregate := ApplicationDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
return AppToModel(a), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-sie83", "Could not find app in list")
}
func (es *ProjectEventstore) ReactivateApplication(ctx context.Context, projectID, appID string) (*proj_model.Application, error) {
if appID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-0odi2", "appID missing")
}
existing, err := es.ProjectByID(ctx, projectID)
if err != nil {
return nil, err
}
app := &proj_model.Application{AppID: appID}
if _, ok := existing.ContainsApp(app); !ok {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld92d", "App is not in this project")
}
repoProject := ProjectFromModel(existing)
repoApp := AppFromModel(app)
projectAggregate := ApplicationReactivatedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
return AppToModel(a), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-sld93", "Could not find app in list")
}
func (es *ProjectEventstore) ChangeOIDCConfig(ctx context.Context, config *proj_model.OIDCConfig) (*proj_model.OIDCConfig, error) {
if config == nil || !config.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-du834", "invalid oidc config")
}
existing, err := es.ProjectByID(ctx, config.AggregateID)
if err != nil {
return nil, err
}
var ok bool
var app *proj_model.Application
if app, ok = existing.ContainsApp(&proj_model.Application{AppID: config.AppID}); !ok {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-dkso8", "App is not in this project")
}
if app.Type != proj_model.APPTYPE_OIDC {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-98uje", "App is not an oidc application")
}
repoProject := ProjectFromModel(existing)
repoConfig := OIDCConfigFromModel(config)
projectAggregate := OIDCConfigChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoConfig)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
return OIDCConfigToModel(a.OIDCConfig), nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Could not find app in list")
}
func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, projectID, appID string) (*proj_model.OIDCConfig, error) {
if appID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-7ue34", "some required fields missing")
}
existing, err := es.ProjectByID(ctx, projectID)
if err != nil {
return nil, err
}
var ok bool
var app *proj_model.Application
if app, ok = existing.ContainsApp(&proj_model.Application{AppID: appID}); !ok {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9odi4", "App is not in this project")
}
if app.Type != proj_model.APPTYPE_OIDC {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-dile4", "App is not an oidc application")
}
repoProject := ProjectFromModel(existing)
stringPw, crypto, err := generateNewClientSecret(es.pwGenerator)
if err != nil {
return nil, err
}
projectAggregate := OIDCConfigSecretChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, appID, crypto)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
es.projectCache.cacheProject(repoProject)
for _, a := range repoProject.Applications {
if a.AppID == app.AppID {
config := OIDCConfigToModel(a.OIDCConfig)
config.ClientSecretString = stringPw
return config, nil
}
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Could not find app in list")
}

View File

@ -3,12 +3,30 @@ package eventsourcing
import (
"encoding/json"
mock_cache "github.com/caos/zitadel/internal/cache/mock"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/eventstore/mock"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/project/model"
"github.com/golang/mock/gomock"
"github.com/sony/sonyflake"
)
func GetMockedEventstore(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *ProjectEventstore {
return &ProjectEventstore{
Eventstore: mockEs,
projectCache: GetMockCache(ctrl),
idGenerator: GetSonyFlacke(),
}
}
func GetMockedEventstoreWithPw(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *ProjectEventstore {
return &ProjectEventstore{
Eventstore: mockEs,
projectCache: GetMockCache(ctrl),
idGenerator: GetSonyFlacke(),
pwGenerator: GetMockPwGenerator(ctrl),
}
}
func GetMockCache(ctrl *gomock.Controller) *ProjectCache {
mockCache := mock_cache.NewMockCache(ctrl)
mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
@ -16,60 +34,133 @@ func GetMockCache(ctrl *gomock.Controller) *ProjectCache {
return &ProjectCache{projectCache: mockCache}
}
func GetSonyFlacke() *sonyflake.Sonyflake {
return sonyflake.NewSonyflake(sonyflake.Settings{})
}
func GetMockPwGenerator(ctrl *gomock.Controller) crypto.Generator {
generator := crypto.NewMockGenerator(ctrl)
generator.EXPECT().Length().Return(uint(10))
generator.EXPECT().Runes().Return([]rune("abcdefghijklmnopqrstuvwxyz"))
generator.EXPECT().Alg().Return(crypto.NewBCrypt(10))
return generator
}
func GetMockProjectByIDOK(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockProjectByIDNoEvents(ctrl *gomock.Controller) *ProjectEventstore {
events := []*es_models.Event{}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProject(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProjectWithPw(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstoreWithPw(ctrl, mockEs)
}
func GetMockManipulateInactiveProject(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "ID", Sequence: 2, Type: model.ProjectDeactivated, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 2, Type: model.ProjectDeactivated, Data: data},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProjectWithMember(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
memberData, _ := json.Marshal(ProjectMember{UserID: "UserID", Roles: []string{"Role"}})
events := []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProjectWithRole(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
roleData, _ := json.Marshal(ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectRoleAdded, Data: roleData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProjectWithOIDCApp(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
appData, _ := json.Marshal(Application{AppID: "AppID", Name: "Name"})
oidcData, _ := json.Marshal(OIDCConfig{
AppID: "AppID",
ResponseTypes: []int32{int32(model.OIDCRESPONSETYPE_CODE)},
GrantTypes: []int32{int32(model.OIDCGRANTTYPE_AUTHORIZATION_CODE)},
})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ApplicationAdded, Data: appData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.OIDCConfigAdded, Data: oidcData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstoreWithPw(ctrl, mockEs)
}
func GetMockManipulateProjectWithSAMLApp(ctrl *gomock.Controller) *ProjectEventstore {
data, _ := json.Marshal(Project{Name: "Name"})
appData, _ := json.Marshal(Application{AppID: "AppID", Name: "Name"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: data},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ApplicationAdded, Data: appData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockManipulateProjectNoEvents(ctrl *gomock.Controller) *ProjectEventstore {
@ -78,17 +169,32 @@ func GetMockManipulateProjectNoEvents(ctrl *gomock.Controller) *ProjectEventstor
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockProjectMemberByIDsOK(ctrl *gomock.Controller) *ProjectEventstore {
projectData, _ := json.Marshal(Project{Name: "Name"})
memberData, _ := json.Marshal(ProjectMember{UserID: "UserID", Roles: []string{"Role"}})
events := []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: projectData},
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: projectData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return &ProjectEventstore{Eventstore: mockEs, projectCache: GetMockCache(ctrl)}
return GetMockedEventstore(ctrl, mockEs)
}
func GetMockProjectAppsByIDsOK(ctrl *gomock.Controller) *ProjectEventstore {
projectData, _ := json.Marshal(Project{Name: "Name"})
appData, _ := json.Marshal(Application{AppID: "AppID", Name: "Name"})
oidcData, _ := json.Marshal(OIDCConfig{ClientID: "ClientID"})
events := []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded, Data: projectData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ApplicationAdded, Data: appData},
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.OIDCConfigAdded, Data: oidcData},
}
mockEs := mock.NewMockEventstore(ctrl)
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
return GetMockedEventstore(ctrl, mockEs)
}

File diff suppressed because it is too large Load Diff

View File

@ -2,11 +2,11 @@ package eventsourcing
import (
"encoding/json"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/project/model"
"reflect"
)
const (
@ -15,9 +15,11 @@ const (
type Project struct {
es_models.ObjectRoot
Name string `json:"name,omitempty"`
State int32 `json:"-"`
Members []*ProjectMember `json:"-"`
Name string `json:"name,omitempty"`
State int32 `json:"-"`
Members []*ProjectMember `json:"-"`
Roles []*ProjectRole `json:"-"`
Applications []*Application `json:"-"`
}
type ProjectMember struct {
@ -26,6 +28,40 @@ type ProjectMember struct {
Roles []string `json:"roles,omitempty"`
}
type ProjectRole struct {
es_models.ObjectRoot
Key string `json:"key,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Group string `json:"group,omitempty"`
}
type Application struct {
es_models.ObjectRoot
AppID string `json:"appId"`
State int32 `json:"-"`
Name string `json:"name,omitempty"`
Type int32 `json:"appType,omitempty"`
OIDCConfig *OIDCConfig `json:"-"`
}
type ApplicationID struct {
es_models.ObjectRoot
AppID string `json:"appId"`
}
type OIDCConfig struct {
es_models.ObjectRoot
AppID string `json:"appId"`
ClientID string `json:"clientId,omitempty"`
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
RedirectUris []string `json:"redirectUris,omitempty"`
ResponseTypes []int32 `json:"responseTypes,omitempty"`
GrantTypes []int32 `json:"grantTypes,omitempty"`
ApplicationType int32 `json:"applicationType,omitempty"`
AuthMethodType int32 `json:"authMethodType,omitempty"`
PostLogoutRedirectUris []string `json:"postLogoutRedirectUris,omitempty"`
}
func (p *Project) Changes(changed *Project) map[string]interface{} {
changes := make(map[string]interface{}, 1)
if changed.Name != "" && p.Name != changed.Name {
@ -34,33 +70,74 @@ func (p *Project) Changes(changed *Project) map[string]interface{} {
return changes
}
func (a *Application) Changes(changed *Application) map[string]interface{} {
changes := make(map[string]interface{}, 1)
changes["appId"] = a.AppID
if changed.Name != "" && a.Name != changed.Name {
changes["name"] = changed.Name
}
return changes
}
func (c *OIDCConfig) Changes(changed *OIDCConfig) map[string]interface{} {
changes := make(map[string]interface{}, 1)
changes["appId"] = c.AppID
if !reflect.DeepEqual(c.RedirectUris, changed.RedirectUris) {
changes["redirectUris"] = changed.RedirectUris
}
if !reflect.DeepEqual(c.ResponseTypes, changed.ResponseTypes) {
changes["responseTypes"] = changed.ResponseTypes
}
if !reflect.DeepEqual(c.GrantTypes, changed.GrantTypes) {
changes["grantTypes"] = changed.GrantTypes
}
if c.ApplicationType != changed.ApplicationType {
changes["applicationType"] = changed.ApplicationType
}
if c.AuthMethodType != changed.AuthMethodType {
changes["authMethodType"] = changed.AuthMethodType
}
if !reflect.DeepEqual(c.PostLogoutRedirectUris, changed.PostLogoutRedirectUris) {
changes["postLogoutRedirectUris"] = changed.PostLogoutRedirectUris
}
return changes
}
func ProjectFromModel(project *model.Project) *Project {
members := ProjectMembersFromModel(project.Members)
roles := ProjectRolesFromModel(project.Roles)
apps := AppsFromModel(project.Applications)
return &Project{
ObjectRoot: es_models.ObjectRoot{
ID: project.ObjectRoot.ID,
AggregateID: project.ObjectRoot.AggregateID,
Sequence: project.Sequence,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
},
Name: project.Name,
State: model.ProjectStateToInt(project.State),
Members: members,
Name: project.Name,
State: int32(project.State),
Members: members,
Roles: roles,
Applications: apps,
}
}
func ProjectToModel(project *Project) *model.Project {
members := ProjectMembersToModel(project.Members)
roles := ProjectRolesToModel(project.Roles)
apps := AppsToModel(project.Applications)
return &model.Project{
ObjectRoot: es_models.ObjectRoot{
ID: project.ID,
AggregateID: project.AggregateID,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
Sequence: project.Sequence,
},
Name: project.Name,
State: model.ProjectStateFromInt(project.State),
Members: members,
Name: project.Name,
State: model.ProjectState(project.State),
Members: members,
Roles: roles,
Applications: apps,
}
}
@ -83,7 +160,7 @@ func ProjectMembersFromModel(members []*model.ProjectMember) []*ProjectMember {
func ProjectMemberFromModel(member *model.ProjectMember) *ProjectMember {
return &ProjectMember{
ObjectRoot: es_models.ObjectRoot{
ID: member.ObjectRoot.ID,
AggregateID: member.ObjectRoot.AggregateID,
Sequence: member.Sequence,
ChangeDate: member.ChangeDate,
CreationDate: member.CreationDate,
@ -96,7 +173,7 @@ func ProjectMemberFromModel(member *model.ProjectMember) *ProjectMember {
func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember {
return &model.ProjectMember{
ObjectRoot: es_models.ObjectRoot{
ID: member.ID,
AggregateID: member.AggregateID,
ChangeDate: member.ChangeDate,
CreationDate: member.CreationDate,
Sequence: member.Sequence,
@ -106,6 +183,160 @@ func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember {
}
}
func ProjectRolesToModel(roles []*ProjectRole) []*model.ProjectRole {
convertedRoles := make([]*model.ProjectRole, len(roles))
for i, r := range roles {
convertedRoles[i] = ProjectRoleToModel(r)
}
return convertedRoles
}
func ProjectRolesFromModel(roles []*model.ProjectRole) []*ProjectRole {
convertedRoles := make([]*ProjectRole, len(roles))
for i, r := range roles {
convertedRoles[i] = ProjectRoleFromModel(r)
}
return convertedRoles
}
func ProjectRoleFromModel(role *model.ProjectRole) *ProjectRole {
return &ProjectRole{
ObjectRoot: es_models.ObjectRoot{
AggregateID: role.ObjectRoot.AggregateID,
Sequence: role.Sequence,
ChangeDate: role.ChangeDate,
CreationDate: role.CreationDate,
},
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}
func ProjectRoleToModel(role *ProjectRole) *model.ProjectRole {
return &model.ProjectRole{
ObjectRoot: es_models.ObjectRoot{
AggregateID: role.AggregateID,
ChangeDate: role.ChangeDate,
CreationDate: role.CreationDate,
Sequence: role.Sequence,
},
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}
func AppsToModel(apps []*Application) []*model.Application {
convertedApps := make([]*model.Application, len(apps))
for i, a := range apps {
convertedApps[i] = AppToModel(a)
}
return convertedApps
}
func AppsFromModel(apps []*model.Application) []*Application {
convertedApps := make([]*Application, len(apps))
for i, a := range apps {
convertedApps[i] = AppFromModel(a)
}
return convertedApps
}
func AppFromModel(app *model.Application) *Application {
converted := &Application{
ObjectRoot: es_models.ObjectRoot{
AggregateID: app.ObjectRoot.AggregateID,
Sequence: app.Sequence,
ChangeDate: app.ChangeDate,
CreationDate: app.CreationDate,
},
AppID: app.AppID,
Name: app.Name,
State: int32(app.State),
Type: int32(app.Type),
}
if app.OIDCConfig != nil {
converted.OIDCConfig = OIDCConfigFromModel(app.OIDCConfig)
}
return converted
}
func AppToModel(app *Application) *model.Application {
converted := &model.Application{
ObjectRoot: es_models.ObjectRoot{
AggregateID: app.AggregateID,
ChangeDate: app.ChangeDate,
CreationDate: app.CreationDate,
Sequence: app.Sequence,
},
AppID: app.AppID,
Name: app.Name,
State: model.AppState(app.State),
Type: model.AppType(app.Type),
}
if app.OIDCConfig != nil {
converted.OIDCConfig = OIDCConfigToModel(app.OIDCConfig)
}
return converted
}
func OIDCConfigFromModel(config *model.OIDCConfig) *OIDCConfig {
responseTypes := make([]int32, len(config.ResponseTypes))
for i, rt := range config.ResponseTypes {
responseTypes[i] = int32(rt)
}
grantTypes := make([]int32, len(config.GrantTypes))
for i, rt := range config.GrantTypes {
grantTypes[i] = int32(rt)
}
return &OIDCConfig{
ObjectRoot: es_models.ObjectRoot{
AggregateID: config.ObjectRoot.AggregateID,
Sequence: config.Sequence,
ChangeDate: config.ChangeDate,
CreationDate: config.CreationDate,
},
AppID: config.AppID,
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
RedirectUris: config.RedirectUris,
ResponseTypes: responseTypes,
GrantTypes: grantTypes,
ApplicationType: int32(config.ApplicationType),
AuthMethodType: int32(config.AuthMethodType),
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
}
}
func OIDCConfigToModel(config *OIDCConfig) *model.OIDCConfig {
responseTypes := make([]model.OIDCResponseType, len(config.ResponseTypes))
for i, rt := range config.ResponseTypes {
responseTypes[i] = model.OIDCResponseType(rt)
}
grantTypes := make([]model.OIDCGrantType, len(config.GrantTypes))
for i, rt := range config.GrantTypes {
grantTypes[i] = model.OIDCGrantType(rt)
}
return &model.OIDCConfig{
ObjectRoot: es_models.ObjectRoot{
AggregateID: config.ObjectRoot.AggregateID,
Sequence: config.Sequence,
ChangeDate: config.ChangeDate,
CreationDate: config.CreationDate,
},
AppID: config.AppID,
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
RedirectUris: config.RedirectUris,
ResponseTypes: responseTypes,
GrantTypes: grantTypes,
ApplicationType: model.OIDCApplicationType(config.ApplicationType),
AuthMethodType: model.OIDCAuthMethodType(config.AuthMethodType),
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
}
}
func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project, error) {
if project == nil {
project = &Project{}
@ -132,7 +363,7 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
logging.Log("EVEN-idl93").WithError(err).Error("could not unmarshal event data")
return err
}
p.State = model.ProjectStateToInt(model.Active)
p.State = int32(model.PROJECTSTATE_ACTIVE)
return nil
case model.ProjectDeactivated:
return p.appendDeactivatedEvent()
@ -144,22 +375,43 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
return p.appendChangeMemberEvent(event)
case model.ProjectMemberRemoved:
return p.appendRemoveMemberEvent(event)
case model.ProjectRoleAdded:
return p.appendAddRoleEvent(event)
case model.ProjectRoleChanged:
return p.appendChangeRoleEvent(event)
case model.ProjectRoleRemoved:
return p.appendRemoveRoleEvent(event)
case model.ApplicationAdded:
return p.appendAddAppEvent(event)
case model.ApplicationChanged:
return p.appendChangeAppEvent(event)
case model.ApplicationRemoved:
return p.appendRemoveAppEvent(event)
case model.ApplicationDeactivated:
return p.appendAppStateEvent(event, model.APPSTATE_INACTIVE)
case model.ApplicationReactivated:
return p.appendAppStateEvent(event, model.APPSTATE_ACTIVE)
case model.OIDCConfigAdded:
return p.appendAddOIDCConfigEvent(event)
case model.OIDCConfigChanged, model.OIDCConfigSecretChanged:
return p.appendChangeOIDCConfigEvent(event)
}
return nil
}
func (p *Project) appendDeactivatedEvent() error {
p.State = model.ProjectStateToInt(model.Inactive)
p.State = int32(model.PROJECTSTATE_INACTIVE)
return nil
}
func (p *Project) appendReactivatedEvent() error {
p.State = model.ProjectStateToInt(model.Active)
p.State = int32(model.PROJECTSTATE_ACTIVE)
return nil
}
func (p *Project) appendAddMemberEvent(event *es_models.Event) error {
member, err := getMemberData(event)
member := &ProjectMember{}
err := member.setData(event)
if err != nil {
return err
}
@ -169,7 +421,8 @@ func (p *Project) appendAddMemberEvent(event *es_models.Event) error {
}
func (p *Project) appendChangeMemberEvent(event *es_models.Event) error {
member, err := getMemberData(event)
member := &ProjectMember{}
err := member.setData(event)
if err != nil {
return err
}
@ -182,7 +435,8 @@ func (p *Project) appendChangeMemberEvent(event *es_models.Event) error {
}
func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error {
member, err := getMemberData(event)
member := &ProjectMember{}
err := member.setData(event)
if err != nil {
return err
}
@ -196,12 +450,165 @@ func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error {
return nil
}
func getMemberData(event *es_models.Event) (*ProjectMember, error) {
member := &ProjectMember{}
member.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, member); err != nil {
func (m *ProjectMember) setData(event *es_models.Event) error {
m.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, m); err != nil {
logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data")
return nil, errors.ThrowInternal(err, "EVENT-83js6", "could not unmarshal event data")
return err
}
return member, nil
return nil
}
func (p *Project) appendAddRoleEvent(event *es_models.Event) error {
role := new(ProjectRole)
err := role.setData(event)
if err != nil {
return err
}
role.ObjectRoot.CreationDate = event.CreationDate
p.Roles = append(p.Roles, role)
return nil
}
func (p *Project) appendChangeRoleEvent(event *es_models.Event) error {
role := new(ProjectRole)
err := role.setData(event)
if err != nil {
return err
}
for i, r := range p.Roles {
if r.Key == role.Key {
p.Roles[i] = role
}
}
return nil
}
func (p *Project) appendRemoveRoleEvent(event *es_models.Event) error {
role := new(ProjectRole)
err := role.setData(event)
if err != nil {
return err
}
for i, r := range p.Roles {
if r.Key == role.Key {
p.Roles[i] = p.Roles[len(p.Roles)-1]
p.Roles[len(p.Roles)-1] = nil
p.Roles = p.Roles[:len(p.Roles)-1]
}
}
return nil
}
func (r *ProjectRole) setData(event *es_models.Event) error {
r.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, r); err != nil {
logging.Log("EVEN-d9euw").WithError(err).Error("could not unmarshal event data")
return err
}
return nil
}
func (p *Project) appendAddAppEvent(event *es_models.Event) error {
app := new(Application)
err := app.setData(event)
if err != nil {
return err
}
app.ObjectRoot.CreationDate = event.CreationDate
p.Applications = append(p.Applications, app)
return nil
}
func (p *Project) appendChangeAppEvent(event *es_models.Event) error {
app := new(Application)
err := app.setData(event)
if err != nil {
return err
}
for i, a := range p.Applications {
if a.AppID == app.AppID {
p.Applications[i].setData(event)
}
}
return nil
}
func (p *Project) appendRemoveAppEvent(event *es_models.Event) error {
app := new(Application)
err := app.setData(event)
if err != nil {
return err
}
for i, a := range p.Applications {
if a.AppID == app.AppID {
p.Applications[i] = p.Applications[len(p.Applications)-1]
p.Applications[len(p.Applications)-1] = nil
p.Applications = p.Applications[:len(p.Applications)-1]
}
}
return nil
}
func (p *Project) appendAppStateEvent(event *es_models.Event, state model.AppState) error {
app := new(Application)
err := app.setData(event)
if err != nil {
return err
}
for i, a := range p.Applications {
if a.AppID == app.AppID {
a.State = int32(state)
p.Applications[i] = a
}
}
return nil
}
func (a *Application) setData(event *es_models.Event) error {
a.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, a); err != nil {
logging.Log("EVEN-8die3").WithError(err).Error("could not unmarshal event data")
return err
}
return nil
}
func (p *Project) appendAddOIDCConfigEvent(event *es_models.Event) error {
config := new(OIDCConfig)
err := config.setData(event)
if err != nil {
return err
}
config.ObjectRoot.CreationDate = event.CreationDate
for i, a := range p.Applications {
if a.AppID == config.AppID {
p.Applications[i].Type = int32(model.APPTYPE_OIDC)
p.Applications[i].OIDCConfig = config
}
}
return nil
}
func (p *Project) appendChangeOIDCConfigEvent(event *es_models.Event) error {
config := new(OIDCConfig)
err := config.setData(event)
if err != nil {
return err
}
for i, a := range p.Applications {
if a.AppID == config.AppID {
p.Applications[i].OIDCConfig.setData(event)
}
}
return nil
}
func (o *OIDCConfig) setData(event *es_models.Event) error {
o.ObjectRoot.AppendEvent(event)
if err := json.Unmarshal(event.Data, o); err != nil {
logging.Log("EVEN-d8e3s").WithError(err).Error("could not unmarshal event data")
return err
}
return nil
}

View File

@ -8,168 +8,7 @@ import (
"github.com/caos/zitadel/internal/project/model"
)
func TestProjectFromEvents(t *testing.T) {
type args struct {
event []*es_models.Event
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "project from events, ok",
args: args{
event: []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded},
},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Active), Name: "ProjectName"},
},
{
name: "project from events, nil project",
args: args{
event: []*es_models.Event{
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded},
},
project: nil,
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Active)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.project != nil {
data, _ := json.Marshal(tt.args.project)
tt.args.event[0].Data = data
}
result, _ := ProjectFromEvents(tt.args.project, tt.args.event...)
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
})
}
}
func TestAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append added event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Active), Name: "ProjectName"},
},
{
name: "append change event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectChanged},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Active), Name: "ProjectName"},
},
{
name: "append deactivate event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectDeactivated},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Inactive)},
},
{
name: "append reactivate event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectReactivated},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{ID: "ID"}, State: int32(model.Active)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.project != nil {
data, _ := json.Marshal(tt.args.project)
tt.args.event.Data = data
}
result := &Project{}
result.AppendEvent(tt.args.event)
if result.State != tt.result.State {
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, result.State)
}
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
if result.ObjectRoot.ID != tt.result.ObjectRoot.ID {
t.Errorf("got wrong result id: expected: %v, actual: %v ", tt.result.ObjectRoot.ID, result.ObjectRoot.ID)
}
})
}
}
func TestAppendDeactivatedEvent(t *testing.T) {
type args struct {
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append reactivate event",
args: args{
project: &Project{},
},
result: &Project{State: int32(model.Inactive)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.project.appendDeactivatedEvent()
if tt.args.project.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
}
})
}
}
func TestAppendReactivatedEvent(t *testing.T) {
type args struct {
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append reactivate event",
args: args{
project: &Project{},
},
result: &Project{State: int32(model.Active)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.project.appendReactivatedEvent()
if tt.args.project.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
}
})
}
}
func TestChanges(t *testing.T) {
func TestProjectChanges(t *testing.T) {
type args struct {
existing *Project
new *Project
@ -213,6 +52,302 @@ func TestChanges(t *testing.T) {
}
}
func TestApplicationChanges(t *testing.T) {
type args struct {
existing *Application
new *Application
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
name: "application name changes",
args: args{
existing: &Application{AppID: "AppID", Name: "Name"},
new: &Application{AppID: "AppID", Name: "NameChanged"},
},
res: res{
changesLen: 2,
},
},
{
name: "no changes",
args: args{
existing: &Application{AppID: "AppID", Name: "Name"},
new: &Application{AppID: "AppID", Name: "Name"},
},
res: res{
changesLen: 1,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.Changes(tt.args.new)
if len(changes) != tt.res.changesLen {
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
}
})
}
}
func TestOIDCConfigChanges(t *testing.T) {
type args struct {
existing *OIDCConfig
new *OIDCConfig
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
name: "all possible values change",
args: args{
existing: &OIDCConfig{
AppID: "AppID",
RedirectUris: []string{"RedirectUris"},
ResponseTypes: []int32{1},
GrantTypes: []int32{1},
ApplicationType: 1,
AuthMethodType: 1,
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
},
new: &OIDCConfig{
AppID: "AppID",
RedirectUris: []string{"RedirectUrisChanged"},
ResponseTypes: []int32{2},
GrantTypes: []int32{2},
ApplicationType: 2,
AuthMethodType: 2,
PostLogoutRedirectUris: []string{"PostLogoutRedirectUrisChanged"},
},
},
res: res{
changesLen: 7,
},
},
{
name: "no changes",
args: args{
existing: &OIDCConfig{
AppID: "AppID",
RedirectUris: []string{"RedirectUris"},
ResponseTypes: []int32{1},
GrantTypes: []int32{1},
ApplicationType: 1,
AuthMethodType: 1,
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
},
new: &OIDCConfig{
AppID: "AppID",
RedirectUris: []string{"RedirectUris"},
ResponseTypes: []int32{1},
GrantTypes: []int32{1},
ApplicationType: 1,
AuthMethodType: 1,
PostLogoutRedirectUris: []string{"PostLogoutRedirectUris"},
},
},
res: res{
changesLen: 1,
},
},
{
name: "change not changeable attributes",
args: args{
existing: &OIDCConfig{
AppID: "AppID",
ClientID: "ClientID",
},
new: &OIDCConfig{
AppID: "AppIDChange",
ClientID: "ClientIDChange",
},
},
res: res{
changesLen: 1,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.Changes(tt.args.new)
if len(changes) != tt.res.changesLen {
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
}
})
}
}
func TestProjectFromEvents(t *testing.T) {
type args struct {
event []*es_models.Event
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "project from events, ok",
args: args{
event: []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
},
{
name: "project from events, nil project",
args: args{
event: []*es_models.Event{
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
},
project: nil,
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.project != nil {
data, _ := json.Marshal(tt.args.project)
tt.args.event[0].Data = data
}
result, _ := ProjectFromEvents(tt.args.project, tt.args.event...)
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
})
}
}
func TestAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append added event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectAdded},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
},
{
name: "append change event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectChanged},
project: &Project{Name: "ProjectName"},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE), Name: "ProjectName"},
},
{
name: "append deactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectDeactivated},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_INACTIVE)},
},
{
name: "append reactivate event",
args: args{
event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.ProjectReactivated},
},
result: &Project{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, State: int32(model.PROJECTSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.project != nil {
data, _ := json.Marshal(tt.args.project)
tt.args.event.Data = data
}
result := new(Project)
result.AppendEvent(tt.args.event)
if result.State != tt.result.State {
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, result.State)
}
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
if result.ObjectRoot.AggregateID != tt.result.ObjectRoot.AggregateID {
t.Errorf("got wrong result id: expected: %v, actual: %v ", tt.result.ObjectRoot.AggregateID, result.ObjectRoot.AggregateID)
}
})
}
}
func TestAppendDeactivatedEvent(t *testing.T) {
type args struct {
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append reactivate event",
args: args{
project: &Project{},
},
result: &Project{State: int32(model.PROJECTSTATE_INACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.project.appendDeactivatedEvent()
if tt.args.project.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
}
})
}
}
func TestAppendReactivatedEvent(t *testing.T) {
type args struct {
project *Project
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append reactivate event",
args: args{
project: &Project{},
},
result: &Project{State: int32(model.PROJECTSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.project.appendReactivatedEvent()
if tt.args.project.State != tt.result.State {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.project)
}
})
}
}
func TestAppendAddMemberEvent(t *testing.T) {
type args struct {
@ -319,7 +454,361 @@ func TestAppendRemoveMemberEvent(t *testing.T) {
}
tt.args.project.appendRemoveMemberEvent(tt.args.event)
if len(tt.args.project.Members) != 0 {
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
t.Errorf("got wrong result should have no member actual: %v ", len(tt.args.project.Members))
}
})
}
}
func TestAppendAddRoleEvent(t *testing.T) {
type args struct {
project *Project
role *ProjectRole
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append add role event",
args: args{
project: &Project{},
role: &ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"},
event: &es_models.Event{},
},
result: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.role != nil {
data, _ := json.Marshal(tt.args.role)
tt.args.event.Data = data
}
tt.args.project.appendAddRoleEvent(tt.args.event)
if len(tt.args.project.Roles) != 1 {
t.Errorf("got wrong result should have one role actual: %v ", len(tt.args.project.Roles))
}
if tt.args.project.Roles[0] == tt.result.Roles[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Roles[0], tt.args.project.Roles[0])
}
})
}
}
func TestAppendChangeRoleEvent(t *testing.T) {
type args struct {
project *Project
role *ProjectRole
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append change role event",
args: args{
project: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
role: &ProjectRole{Key: "Key", DisplayName: "DisplayNameChanged", Group: "Group"},
event: &es_models.Event{},
},
result: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayNameChanged", Group: "Group"}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.role != nil {
data, _ := json.Marshal(tt.args.role)
tt.args.event.Data = data
}
tt.args.project.appendChangeRoleEvent(tt.args.event)
if len(tt.args.project.Roles) != 1 {
t.Errorf("got wrong result should have one role actual: %v ", len(tt.args.project.Roles))
}
if tt.args.project.Roles[0] == tt.result.Roles[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Roles[0], tt.args.project.Roles[0])
}
})
}
}
func TestAppendRemoveRoleEvent(t *testing.T) {
type args struct {
project *Project
role *ProjectRole
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append remove role event",
args: args{
project: &Project{Roles: []*ProjectRole{&ProjectRole{Key: "Key", DisplayName: "DisplayName", Group: "Group"}}},
role: &ProjectRole{Key: "Key"},
event: &es_models.Event{},
},
result: &Project{Roles: []*ProjectRole{}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.role != nil {
data, _ := json.Marshal(tt.args.role)
tt.args.event.Data = data
}
tt.args.project.appendRemoveRoleEvent(tt.args.event)
if len(tt.args.project.Roles) != 0 {
t.Errorf("got wrong result should have no role actual: %v ", len(tt.args.project.Roles))
}
})
}
}
func TestAppendAddAppEvent(t *testing.T) {
type args struct {
project *Project
app *Application
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append add application event",
args: args{
project: &Project{},
app: &Application{Name: "Application"},
event: &es_models.Event{},
},
result: &Project{Applications: []*Application{&Application{Name: "Application"}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.app != nil {
data, _ := json.Marshal(tt.args.app)
tt.args.event.Data = data
}
tt.args.project.appendAddAppEvent(tt.args.event)
if len(tt.args.project.Applications) != 1 {
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
}
if tt.args.project.Applications[0] == tt.result.Applications[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
}
})
}
}
func TestAppendChangeAppEvent(t *testing.T) {
type args struct {
project *Project
app *Application
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append change application event",
args: args{
project: &Project{Applications: []*Application{&Application{Name: "Application"}}},
app: &Application{Name: "Application Change"},
event: &es_models.Event{},
},
result: &Project{Applications: []*Application{&Application{Name: "Application Change"}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.app != nil {
data, _ := json.Marshal(tt.args.app)
tt.args.event.Data = data
}
tt.args.project.appendChangeAppEvent(tt.args.event)
if len(tt.args.project.Applications) != 1 {
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
}
if tt.args.project.Applications[0] == tt.result.Applications[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
}
})
}
}
func TestAppendRemoveAppEvent(t *testing.T) {
type args struct {
project *Project
app *Application
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append remove application event",
args: args{
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application"}}},
app: &Application{AppID: "AppID", Name: "Application"},
event: &es_models.Event{},
},
result: &Project{Applications: []*Application{}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.app != nil {
data, _ := json.Marshal(tt.args.app)
tt.args.event.Data = data
}
tt.args.project.appendRemoveAppEvent(tt.args.event)
if len(tt.args.project.Applications) != 0 {
t.Errorf("got wrong result should have no apps actual: %v ", len(tt.args.project.Applications))
}
})
}
}
func TestAppendAppStateEvent(t *testing.T) {
type args struct {
project *Project
app *ApplicationID
event *es_models.Event
state model.AppState
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append deactivate application event",
args: args{
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_ACTIVE)}}},
app: &ApplicationID{AppID: "AppID"},
event: &es_models.Event{},
state: model.APPSTATE_INACTIVE,
},
result: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_INACTIVE)}}},
},
{
name: "append reactivate application event",
args: args{
project: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_INACTIVE)}}},
app: &ApplicationID{AppID: "AppID"},
event: &es_models.Event{},
state: model.APPSTATE_ACTIVE,
},
result: &Project{Applications: []*Application{&Application{AppID: "AppID", Name: "Application", State: int32(model.APPSTATE_ACTIVE)}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.app != nil {
data, _ := json.Marshal(tt.args.app)
tt.args.event.Data = data
}
tt.args.project.appendAppStateEvent(tt.args.event, tt.args.state)
if len(tt.args.project.Applications) != 1 {
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
}
if tt.args.project.Applications[0] == tt.result.Applications[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
}
})
}
}
func TestAppendAddOIDCConfigEvent(t *testing.T) {
type args struct {
project *Project
config *OIDCConfig
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append add application event",
args: args{
project: &Project{Applications: []*Application{&Application{AppID: "AppID"}}},
config: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"},
event: &es_models.Event{},
},
result: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"}}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.config != nil {
data, _ := json.Marshal(tt.args.config)
tt.args.event.Data = data
}
tt.args.project.appendAddOIDCConfigEvent(tt.args.event)
if len(tt.args.project.Applications) != 1 {
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
}
if tt.args.project.Applications[0].OIDCConfig == nil {
t.Errorf("got wrong result should have oidc config actual: %v ", tt.args.project.Applications[0].OIDCConfig)
}
if tt.args.project.Applications[0] == tt.result.Applications[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
}
})
}
}
func TestAppendChangeOIDCConfigEvent(t *testing.T) {
type args struct {
project *Project
config *OIDCConfig
event *es_models.Event
}
tests := []struct {
name string
args args
result *Project
}{
{
name: "append change application event",
args: args{
project: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID"}}}},
config: &OIDCConfig{AppID: "AppID", ClientID: "ClientID Changed"},
event: &es_models.Event{},
},
result: &Project{Applications: []*Application{&Application{AppID: "AppID", OIDCConfig: &OIDCConfig{AppID: "AppID", ClientID: "ClientID Changed"}}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.config != nil {
data, _ := json.Marshal(tt.args.config)
tt.args.event.Data = data
}
tt.args.project.appendChangeOIDCConfigEvent(tt.args.event)
if len(tt.args.project.Applications) != 1 {
t.Errorf("got wrong result should have one app actual: %v ", len(tt.args.project.Applications))
}
if tt.args.project.Applications[0].OIDCConfig == nil {
t.Errorf("got wrong result should have oidc config actual: %v ", tt.args.project.Applications[0].OIDCConfig)
}
if tt.args.project.Applications[0] == tt.result.Applications[0] {
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Applications[0], tt.args.project.Applications[0])
}
})
}

View File

@ -0,0 +1,30 @@
package eventsourcing
import (
"fmt"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/project/model"
"github.com/sony/sonyflake"
"strings"
)
//ClientID random_number@projectname (eg. 495894098234@zitadel)
func generateNewClientID(idGenerator *sonyflake.Sonyflake, project *model.Project) (string, error) {
rndID, err := idGenerator.NextID()
if err != nil {
return "", err
}
return fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_")), nil
}
func generateNewClientSecret(pwGenerator crypto.Generator) (string, *crypto.CryptoValue, error) {
cryptoValue, stringSecret, err := crypto.NewCode(pwGenerator)
if err != nil {
logging.Log("APP-UpnTI").OnError(err).Error("unable to create client secret")
return "", nil, errors.ThrowInternal(err, "APP-gH2Wl", "unable to create password")
}
return stringSecret, cryptoValue, nil
}

View File

@ -2,17 +2,13 @@ package eventsourcing
import (
"context"
"strconv"
"github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/project/model"
"github.com/sony/sonyflake"
)
var idGenerator = sonyflake.NewSonyflake(sonyflake.Settings{})
func ProjectByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
if id == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
@ -27,8 +23,11 @@ func ProjectQuery(latestSequence uint64) *es_models.SearchQuery {
LatestSequenceFilter(latestSequence)
}
func ProjectAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, id string, sequence uint64) (*es_models.Aggregate, error) {
return aggCreator.NewAggregate(ctx, id, model.ProjectAggregate, projectVersion, sequence)
func ProjectAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, project *Project) (*es_models.Aggregate, error) {
if project == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-doe93", "existing project should not be nil")
}
return aggCreator.NewAggregate(ctx, project.AggregateID, model.ProjectAggregate, projectVersion, project.Sequence)
}
func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
@ -36,14 +35,8 @@ func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *Pro
if project == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie6", "project should not be nil")
}
var err error
id, err := idGenerator.NextID()
if err != nil {
return nil, err
}
project.ID = strconv.FormatUint(id, 10)
agg, err := ProjectAggregate(ctx, aggCreator, project.ID, project.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, project)
if err != nil {
return nil, err
}
@ -54,13 +47,10 @@ func ProjectCreateAggregate(aggCreator *es_models.AggregateCreator, project *Pro
func ProjectUpdateAggregate(aggCreator *es_models.AggregateCreator, existing *Project, new *Project) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk93d", "existing project should not be nil")
}
if new == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "new project should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
@ -79,10 +69,7 @@ func ProjectReactivateAggregate(aggCreator *es_models.AggregateCreator, project
func projectStateAggregate(aggCreator *es_models.AggregateCreator, project *Project, state models.EventType) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if project == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-37dur", "existing project should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, project.ID, project.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, project)
if err != nil {
return nil, err
}
@ -92,10 +79,10 @@ func projectStateAggregate(aggCreator *es_models.AggregateCreator, project *Proj
func ProjectMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-di38f", "existing project should not be nil")
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-ie34f", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
@ -105,11 +92,11 @@ func ProjectMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existin
func ProjectMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sle3d", "existing project should not be nil")
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d34fs", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
@ -119,13 +106,174 @@ func ProjectMemberChangedAggregate(aggCreator *es_models.AggregateCreator, exist
func ProjectMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-slo9e", "existing project should not be nil")
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dieu7", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectMemberRemoved, member)
}
}
func ProjectRoleAddedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, role *ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sleo9", "role should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectRoleAdded, role)
}
}
func ProjectRoleChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, role *ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-oe8sf", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectRoleChanged, role)
}
}
func ProjectRoleRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, role *ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d8eis", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectRoleRemoved, role)
}
}
func ApplicationAddedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, app *Application) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if app == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-09du7", "app should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
agg.AppendEvent(model.ApplicationAdded, app)
if app.OIDCConfig != nil {
agg.AppendEvent(model.OIDCConfigAdded, app.OIDCConfig)
}
return agg, nil
}
}
func ApplicationChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, app *Application) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if app == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sleo9", "app should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
var changes map[string]interface{}
for _, a := range existing.Applications {
if a.AppID == app.AppID {
changes = a.Changes(app)
}
}
agg.AppendEvent(model.ApplicationChanged, changes)
return agg, nil
}
}
func ApplicationRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, app *Application) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if app == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-se23g", "app should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
agg.AppendEvent(model.ApplicationRemoved, &ApplicationID{AppID: app.AppID})
return agg, nil
}
}
func ApplicationDeactivatedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, app *Application) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if app == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-slfi3", "app should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
agg.AppendEvent(model.ApplicationDeactivated, &ApplicationID{AppID: app.AppID})
return agg, nil
}
}
func ApplicationReactivatedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, app *Application) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if app == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-slf32", "app should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
agg.AppendEvent(model.ApplicationReactivated, &ApplicationID{AppID: app.AppID})
return agg, nil
}
}
func OIDCConfigChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, config *OIDCConfig) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if config == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-slf32", "config should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
var changes map[string]interface{}
for _, a := range existing.Applications {
if a.AppID == config.AppID {
if a.OIDCConfig != nil {
changes = a.OIDCConfig.Changes(config)
}
}
}
agg.AppendEvent(model.OIDCConfigChanged, changes)
return agg, nil
}
}
func OIDCConfigSecretChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, appID string, secret *crypto.CryptoValue) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
changes := make(map[string]interface{}, 1)
changes["appId"] = appID
changes["clientSecret"] = secret
agg.AppendEvent(model.OIDCConfigSecretChanged, changes)
return agg, nil
}
}

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@ import (
func Test_ToPBStruct(t *testing.T) {
type obj struct {
ID string
Seq uint64
AggregateID string
Seq uint64
}
type args struct {
obj obj
@ -24,11 +24,11 @@ func Test_ToPBStruct(t *testing.T) {
{
name: "to pb stuct",
args: args{
obj: obj{ID: "ID", Seq: 12345},
obj: obj{AggregateID: "AggregateID", Seq: 12345},
},
wantErr: false,
length: 2,
result: obj{ID: "ID", Seq: 12345},
result: obj{AggregateID: "AggregateID", Seq: 12345},
},
{
name: "empty struct",
@ -37,7 +37,7 @@ func Test_ToPBStruct(t *testing.T) {
},
wantErr: false,
length: 2,
result: obj{ID: "", Seq: 0},
result: obj{AggregateID: "", Seq: 0},
},
}
for _, tt := range tests {
@ -49,8 +49,8 @@ func Test_ToPBStruct(t *testing.T) {
if !tt.wantErr && len(fields.Fields) != tt.length {
t.Errorf("got wrong result length, expecting: %v, actual: %v ", tt.length, len(fields.Fields))
}
if !tt.wantErr && tt.result.ID != fields.Fields["ID"].GetStringValue() {
t.Errorf("got wrong result, ID should be same: expecting: %v, actual: %v ", tt.result.ID, fields.Fields["ID"].GetStringValue())
if !tt.wantErr && tt.result.AggregateID != fields.Fields["AggregateID"].GetStringValue() {
t.Errorf("got wrong result, AggregateID should be same: expecting: %v, actual: %v ", tt.result.AggregateID, fields.Fields["AggregateID"].GetStringValue())
}
if !tt.wantErr && int(tt.result.Seq) != int(fields.Fields["Seq"].GetNumberValue()) {
t.Errorf("got wrong result, Seq should be same: expecting: %v, actual: %v ", tt.result.Seq, fields.Fields["Seq"].GetStringValue())
@ -61,8 +61,8 @@ func Test_ToPBStruct(t *testing.T) {
func Test_FromPBStruct(t *testing.T) {
type obj struct {
ID string
Seq uint64
AggregateID string
Seq uint64
}
type args struct {
obj *obj
@ -79,23 +79,22 @@ func Test_FromPBStruct(t *testing.T) {
args: args{
obj: &obj{},
fields: &pb_struct.Struct{Fields: map[string]*pb_struct.Value{
"ID": &pb_struct.Value{Kind: &pb_struct.Value_StringValue{StringValue: "ID"}},
"Seq": &pb_struct.Value{Kind: &pb_struct.Value_NumberValue{NumberValue: 12345}},
"AggregateID": &pb_struct.Value{Kind: &pb_struct.Value_StringValue{StringValue: "AggregateID"}},
"Seq": &pb_struct.Value{Kind: &pb_struct.Value_NumberValue{NumberValue: 12345}},
},
},
},
wantErr: false,
result: obj{ID: "ID", Seq: 12345},
result: obj{AggregateID: "AggregateID", Seq: 12345},
},
{
name: "no fields",
args: args{
obj: &obj{},
fields: &pb_struct.Struct{Fields: map[string]*pb_struct.Value{},
},
obj: &obj{},
fields: &pb_struct.Struct{Fields: map[string]*pb_struct.Value{}},
},
wantErr: false,
result: obj{ID: "", Seq: 0},
result: obj{AggregateID: "", Seq: 0},
},
}
for _, tt := range tests {
@ -104,8 +103,8 @@ func Test_FromPBStruct(t *testing.T) {
if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err)
}
if !tt.wantErr && tt.result.ID != tt.args.obj.ID {
t.Errorf("got wrong result, ID should be same: expecting: %v, actual: %v ", tt.result.ID, tt.args.obj.ID)
if !tt.wantErr && tt.result.AggregateID != tt.args.obj.AggregateID {
t.Errorf("got wrong result, AggregateID should be same: expecting: %v, actual: %v ", tt.result.AggregateID, tt.args.obj.AggregateID)
}
if !tt.wantErr && int(tt.result.Seq) != int(tt.args.obj.Seq) {
t.Errorf("got wrong result, Seq should be same: expecting: %v, actual: %v ", tt.result.Seq, tt.args.obj.Seq)

View File

@ -91,10 +91,10 @@ func TestPrepareSearchQuery(t *testing.T) {
{
"search with search query",
mockDB(t).
expectGetSearchRequestWithSearchQuery("TESTTABLE", TestSearchKey_ID.ToColumnName(), "=", "ID", 2, 2),
expectGetSearchRequestWithSearchQuery("TESTTABLE", TestSearchKey_ID.ToColumnName(), "=", "AggregateID", 2, 2),
args{
table: "TESTTABLE",
searchRequest: TestSearchRequest{queries: []SearchQuery{TestSearchQuery{key: TestSearchKey_ID, method: model.SEARCHMETHOD_EQUALS_IGNORE_CASE, value: "ID"}}},
searchRequest: TestSearchRequest{queries: []SearchQuery{TestSearchQuery{key: TestSearchKey_ID, method: model.SEARCHMETHOD_EQUALS_IGNORE_CASE, value: "AggregateID"}}},
},
res{
count: 2,
@ -104,10 +104,10 @@ func TestPrepareSearchQuery(t *testing.T) {
{
"search with all params",
mockDB(t).
expectGetSearchRequestWithAllParams("TESTTABLE", TestSearchKey_ID.ToColumnName(), "=", "ID", "ASC", TestSearchKey_ID, 2, 2, 2, 5),
expectGetSearchRequestWithAllParams("TESTTABLE", TestSearchKey_ID.ToColumnName(), "=", "AggregateID", "ASC", TestSearchKey_ID, 2, 2, 2, 5),
args{
table: "TESTTABLE",
searchRequest: TestSearchRequest{limit: 2, offset: 2, sortingColumn: TestSearchKey_ID, asc: true, queries: []SearchQuery{TestSearchQuery{key: TestSearchKey_ID, method: model.SEARCHMETHOD_EQUALS_IGNORE_CASE, value: "ID"}}},
searchRequest: TestSearchRequest{limit: 2, offset: 2, sortingColumn: TestSearchKey_ID, asc: true, queries: []SearchQuery{TestSearchQuery{key: TestSearchKey_ID, method: model.SEARCHMETHOD_EQUALS_IGNORE_CASE, value: "AggregateID"}}},
},
res{
count: 5,

View File

@ -20,7 +20,7 @@ func PrepareGetByKey(table string, key ColumnKey, id string) func(db *gorm.DB, r
if errors.Is(err, gorm.ErrRecordNotFound) {
return caos_errs.ThrowNotFound(err, "VIEW-XRI9c", "object not found")
}
logging.LogWithFields("VIEW-xVShS", "ID", id).WithError(err).Warn("get from view error")
logging.LogWithFields("VIEW-xVShS", "AggregateID", id).WithError(err).Warn("get from view error")
return caos_errs.ThrowInternal(err, "VIEW-J92Td", "view error")
}
}

View File

@ -270,11 +270,11 @@ func TestPreparePut(t *testing.T) {
"ok",
mockDB(t).
expectBegin(nil).
expectSave("TESTTABLE", Test{ID: "ID", Test: "VALUE"}).
expectSave("TESTTABLE", Test{ID: "AggregateID", Test: "VALUE"}).
expectCommit(nil),
args{
table: "TESTTABLE",
object: &Test{ID: "ID", Test: "VALUE"},
object: &Test{ID: "AggregateID", Test: "VALUE"},
},
res{
result: Test{ID: "VALUE"},
@ -285,11 +285,11 @@ func TestPreparePut(t *testing.T) {
"db error",
mockDB(t).
expectBegin(nil).
expectSaveErr("TESTTABLE", Test{ID: "ID", Test: "VALUE"}, gorm.ErrUnaddressable).
expectSaveErr("TESTTABLE", Test{ID: "AggregateID", Test: "VALUE"}, gorm.ErrUnaddressable).
expectCommit(nil),
args{
table: "TESTTABLE",
object: &Test{ID: "ID", Test: "VALUE"},
object: &Test{ID: "AggregateID", Test: "VALUE"},
},
res{
result: Test{ID: "VALUE"},

View File

@ -3,33 +3,69 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/errors"
"github.com/golang/protobuf/ptypes/empty"
)
func (s *Server) SearchApplications(ctx context.Context, request *ApplicationSearchRequest) (*ApplicationSearchResponse, error) {
func (s *Server) SearchApplications(ctx context.Context, in *ApplicationSearchRequest) (*ApplicationSearchResponse, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-yW23f", "Not implemented")
}
func (s *Server) ApplicationByID(ctx context.Context, request *ApplicationID) (*Application, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-bmr6X", "Not implemented")
func (s *Server) ApplicationByID(ctx context.Context, in *ApplicationID) (*Application, error) {
app, err := s.project.ApplicationByID(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) CreateOIDCApplication(ctx context.Context, in *OIDCApplicationCreate) (*Application, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-poe4d", "Not implemented")
app, err := s.project.AddApplication(ctx, oidcAppCreateToModel(in))
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) UpdateApplication(ctx context.Context, in *ApplicationUpdate) (*Application, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-bmt6J", "Not implemented")
app, err := s.project.ChangeApplication(ctx, appUpdateToModel(in))
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) DeactivateApplication(ctx context.Context, in *ApplicationID) (*Application, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-cD34f", "Not implemented")
app, err := s.project.DeactivateApplication(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) ReactivateApplication(ctx context.Context, in *ApplicationID) (*Application, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-mo98S", "Not implemented")
app, err := s.project.ReactivateApplication(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return appFromModel(app), nil
}
func (s *Server) RemoveApplication(ctx context.Context, in *ApplicationID) (*empty.Empty, error) {
err := s.project.RemoveApplication(ctx, in.ProjectId, in.Id)
return &empty.Empty{}, err
}
func (s *Server) UpdateApplicationOIDCConfig(ctx context.Context, in *OIDCConfigUpdate) (*OIDCConfig, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-xm56g", "Not implemented")
config, err := s.project.ChangeOIDCConfig(ctx, oidcConfigUpdateToModel(in))
if err != nil {
return nil, err
}
return oidcConfigFromModel(config), nil
}
func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *ApplicationID) (*ClientSecret, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-dlwp3", "Not implemented")
config, err := s.project.ChangeOIDConfigSecret(ctx, in.ProjectId, in.Id)
if err != nil {
return nil, err
}
return &ClientSecret{ClientSecret: config.ClientSecretString}, nil
}
func (s *Server) ApplicationChanges(ctx context.Context, changesRequest *ChangeRequest) (*Changes, error) {

View File

@ -0,0 +1,225 @@
package grpc
import (
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/models"
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/golang/protobuf/ptypes"
)
func appFromModel(app *proj_model.Application) *Application {
creationDate, err := ptypes.TimestampProto(app.CreationDate)
logging.Log("GRPC-iejs3").OnError(err).Debug("unable to parse timestamp")
changeDate, err := ptypes.TimestampProto(app.ChangeDate)
logging.Log("GRPC-di7rw").OnError(err).Debug("unable to parse timestamp")
return &Application{
Id: app.AppID,
State: appStateFromModel(app.State),
CreationDate: creationDate,
ChangeDate: changeDate,
Name: app.Name,
Sequence: app.Sequence,
AppConfig: appConfigFromModel(app),
}
}
func appConfigFromModel(app *proj_model.Application) isApplication_AppConfig {
if app.Type == proj_model.APPTYPE_OIDC {
return &Application_OidcConfig{
OidcConfig: oidcConfigFromModel(app.OIDCConfig),
}
}
return nil
}
func oidcConfigFromModel(config *proj_model.OIDCConfig) *OIDCConfig {
return &OIDCConfig{
RedirectUris: config.RedirectUris,
ResponseTypes: oidcResponseTypesFromModel(config.ResponseTypes),
GrantTypes: oidcGrantTypesFromModel(config.GrantTypes),
ApplicationType: oidcApplicationTypeFromModel(config.ApplicationType),
ClientId: config.ClientID,
ClientSecret: config.ClientSecretString,
AuthMethodType: oidcAuthMethodTypeFromModel(config.AuthMethodType),
PostLogoutRedirectUris: config.PostLogoutRedirectUris,
}
}
func oidcAppCreateToModel(app *OIDCApplicationCreate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
Name: app.Name,
Type: proj_model.APPTYPE_OIDC,
OIDCConfig: &proj_model.OIDCConfig{
RedirectUris: app.RedirectUris,
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
},
}
}
func appUpdateToModel(app *ApplicationUpdate) *proj_model.Application {
return &proj_model.Application{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
AppID: app.Id,
Name: app.Name,
}
}
func oidcConfigUpdateToModel(app *OIDCConfigUpdate) *proj_model.OIDCConfig {
return &proj_model.OIDCConfig{
ObjectRoot: models.ObjectRoot{
AggregateID: app.ProjectId,
},
AppID: app.ApplicationId,
RedirectUris: app.RedirectUris,
ResponseTypes: oidcResponseTypesToModel(app.ResponseTypes),
GrantTypes: oidcGrantTypesToModel(app.GrantTypes),
ApplicationType: oidcApplicationTypeToModel(app.ApplicationType),
AuthMethodType: oidcAuthMethodTypeToModel(app.AuthMethodType),
PostLogoutRedirectUris: app.PostLogoutRedirectUris,
}
}
func appStateFromModel(state proj_model.AppState) AppState {
switch state {
case proj_model.APPSTATE_ACTIVE:
return AppState_APPSTATE_ACTIVE
case proj_model.APPSTATE_INACTIVE:
return AppState_APPSTATE_INACTIVE
default:
return AppState_APPSTATE_UNSPECIFIED
}
}
func oidcResponseTypesToModel(responseTypes []OIDCResponseType) []proj_model.OIDCResponseType {
if responseTypes == nil || len(responseTypes) == 0 {
return []proj_model.OIDCResponseType{proj_model.OIDCRESPONSETYPE_CODE}
}
oidcResponseTypes := make([]proj_model.OIDCResponseType, len(responseTypes))
for i, responseType := range responseTypes {
switch responseType {
case OIDCResponseType_OIDCRESPONSETYPE_CODE:
oidcResponseTypes[i] = proj_model.OIDCRESPONSETYPE_CODE
case OIDCResponseType_OIDCRESPONSETYPE_ID_TOKEN:
oidcResponseTypes[i] = proj_model.OIDCRESPONSETYPE_ID_TOKEN
case OIDCResponseType_OIDCRESPONSETYPE_TOKEN:
oidcResponseTypes[i] = proj_model.OIDCRESPONSETYPE_TOKEN
}
}
return oidcResponseTypes
}
func oidcResponseTypesFromModel(responseTypes []proj_model.OIDCResponseType) []OIDCResponseType {
oidcResponseTypes := make([]OIDCResponseType, len(responseTypes))
for i, responseType := range responseTypes {
switch responseType {
case proj_model.OIDCRESPONSETYPE_CODE:
oidcResponseTypes[i] = OIDCResponseType_OIDCRESPONSETYPE_CODE
case proj_model.OIDCRESPONSETYPE_ID_TOKEN:
oidcResponseTypes[i] = OIDCResponseType_OIDCRESPONSETYPE_ID_TOKEN
case proj_model.OIDCRESPONSETYPE_TOKEN:
oidcResponseTypes[i] = OIDCResponseType_OIDCRESPONSETYPE_TOKEN
}
}
return oidcResponseTypes
}
func oidcGrantTypesToModel(grantTypes []OIDCGrantType) []proj_model.OIDCGrantType {
if grantTypes == nil || len(grantTypes) == 0 {
return []proj_model.OIDCGrantType{proj_model.OIDCGRANTTYPE_AUTHORIZATION_CODE}
}
oidcGrantTypes := make([]proj_model.OIDCGrantType, len(grantTypes))
for i, grantType := range grantTypes {
switch grantType {
case OIDCGrantType_OIDCGRANTTYPE_AUTHORIZATION_CODE:
oidcGrantTypes[i] = proj_model.OIDCGRANTTYPE_AUTHORIZATION_CODE
case OIDCGrantType_OIDCGRANTTYPE_IMPLICIT:
oidcGrantTypes[i] = proj_model.OIDCGRANTTYPE_IMPLICIT
case OIDCGrantType_OIDCGRANTTYPE_REFRESH_TOKEN:
oidcGrantTypes[i] = proj_model.OIDCGRANTTYPE_REFRESH_TOKEN
}
}
return oidcGrantTypes
}
func oidcGrantTypesFromModel(grantTypes []proj_model.OIDCGrantType) []OIDCGrantType {
oidcGrantTypes := make([]OIDCGrantType, len(grantTypes))
for i, grantType := range grantTypes {
switch grantType {
case proj_model.OIDCGRANTTYPE_AUTHORIZATION_CODE:
oidcGrantTypes[i] = OIDCGrantType_OIDCGRANTTYPE_AUTHORIZATION_CODE
case proj_model.OIDCGRANTTYPE_IMPLICIT:
oidcGrantTypes[i] = OIDCGrantType_OIDCGRANTTYPE_IMPLICIT
case proj_model.OIDCGRANTTYPE_REFRESH_TOKEN:
oidcGrantTypes[i] = OIDCGrantType_OIDCGRANTTYPE_REFRESH_TOKEN
}
}
return oidcGrantTypes
}
func oidcApplicationTypeToModel(appType OIDCApplicationType) proj_model.OIDCApplicationType {
switch appType {
case OIDCApplicationType_OIDCAPPLICATIONTYPE_WEB:
return proj_model.OIDCAPPLICATIONTYPE_WEB
case OIDCApplicationType_OIDCAPPLICATIONTYPE_USER_AGENT:
return proj_model.OIDCAPPLICATIONTYPE_USER_AGENT
case OIDCApplicationType_OIDCAPPLICATIONTYPE_NATIVE:
return proj_model.OIDCAPPLICATIONTYPE_NATIVE
}
return proj_model.OIDCAPPLICATIONTYPE_WEB
}
func oidcApplicationTypeFromModel(appType proj_model.OIDCApplicationType) OIDCApplicationType {
switch appType {
case proj_model.OIDCAPPLICATIONTYPE_WEB:
return OIDCApplicationType_OIDCAPPLICATIONTYPE_WEB
case proj_model.OIDCAPPLICATIONTYPE_USER_AGENT:
return OIDCApplicationType_OIDCAPPLICATIONTYPE_USER_AGENT
case proj_model.OIDCAPPLICATIONTYPE_NATIVE:
return OIDCApplicationType_OIDCAPPLICATIONTYPE_NATIVE
default:
return OIDCApplicationType_OIDCAPPLICATIONTYPE_WEB
}
}
func oidcAuthMethodTypeToModel(authType OIDCAuthMethodType) proj_model.OIDCAuthMethodType {
switch authType {
case OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC:
return proj_model.OIDCAUTHMETHODTYPE_BASIC
case OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST:
return proj_model.OIDCAUTHMETHODTYPE_POST
case OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE:
return proj_model.OIDCAUTHMETHODTYPE_NONE
default:
return proj_model.OIDCAUTHMETHODTYPE_BASIC
}
}
func oidcAuthMethodTypeFromModel(authType proj_model.OIDCAuthMethodType) OIDCAuthMethodType {
switch authType {
case proj_model.OIDCAUTHMETHODTYPE_BASIC:
return OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC
case proj_model.OIDCAUTHMETHODTYPE_POST:
return OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST
case proj_model.OIDCAUTHMETHODTYPE_NONE:
return OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE
default:
return OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC
}
}

View File

@ -325,6 +325,11 @@ var ManagementService_AuthMethods = utils_auth.MethodMapping{
CheckParam: "Id",
},
"/caos.zitadel.management.api.v1.ManagementService/ChangeProjectRole": utils_auth.Option{
Permission: "project.role.write",
CheckParam: "Id",
},
"/caos.zitadel.management.api.v1.ManagementService/RemoveProjectRole": utils_auth.Option{
Permission: "project.role.delete",
CheckParam: "Id",
@ -360,6 +365,11 @@ var ManagementService_AuthMethods = utils_auth.MethodMapping{
CheckParam: "ProjectId",
},
"/caos.zitadel.management.api.v1.ManagementService/RemoveApplication": utils_auth.Option{
Permission: "project.app.delete",
CheckParam: "ProjectId",
},
"/caos.zitadel.management.api.v1.ManagementService/UpdateApplicationOIDCConfig": utils_auth.Option{
Permission: "project.app.write",
CheckParam: "ProjectId",

File diff suppressed because it is too large Load Diff

View File

@ -1860,6 +1860,52 @@ func request_ManagementService_AddProjectRole_0(ctx context.Context, marshaler r
}
func request_ManagementService_ChangeProjectRole_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectRoleChange
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
val, ok = pathParams["key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key")
}
protoReq.Key, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err)
}
msg, err := client.ChangeProjectRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_RemoveProjectRole_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectRoleRemove
var metadata runtime.ServerMetadata
@ -1882,15 +1928,15 @@ func request_ManagementService_RemoveProjectRole_0(ctx context.Context, marshale
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
val, ok = pathParams["name"]
val, ok = pathParams["key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key")
}
protoReq.Name, err = runtime.String(val)
protoReq.Key, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err)
}
msg, err := client.RemoveProjectRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
@ -2144,6 +2190,44 @@ func request_ManagementService_ReactivateApplication_0(ctx context.Context, mars
}
func request_ManagementService_RemoveApplication_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ApplicationID
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["project_id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project_id")
}
protoReq.ProjectId, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project_id", err)
}
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.RemoveApplication(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_UpdateApplicationOIDCConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OIDCConfigUpdate
var metadata runtime.ServerMetadata
@ -4874,6 +4958,26 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se
})
mux.Handle("PUT", pattern_ManagementService_ChangeProjectRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_ChangeProjectRole_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_ChangeProjectRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_RemoveProjectRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -5014,6 +5118,26 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se
})
mux.Handle("DELETE", pattern_ManagementService_RemoveApplication_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_RemoveApplication_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_RemoveApplication_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PUT", pattern_ManagementService_UpdateApplicationOIDCConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -5788,7 +5912,9 @@ var (
pattern_ManagementService_AddProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"projects", "id", "roles"}, ""))
pattern_ManagementService_RemoveProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "id", "roles", "name"}, ""))
pattern_ManagementService_ChangeProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "id", "roles", "key"}, ""))
pattern_ManagementService_RemoveProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "id", "roles", "key"}, ""))
pattern_ManagementService_SearchApplications_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 2, 3}, []string{"projects", "project_id", "applications", "_search"}, ""))
@ -5802,6 +5928,8 @@ var (
pattern_ManagementService_ReactivateApplication_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"projects", "project_id", "applications", "id", "_reactivate"}, ""))
pattern_ManagementService_RemoveApplication_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "project_id", "applications", "id"}, ""))
pattern_ManagementService_UpdateApplicationOIDCConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"projects", "project_id", "applications", "application_id", "oidcconfig"}, ""))
pattern_ManagementService_RegenerateOIDCClientSecret_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 2, 5}, []string{"projects", "project_id", "applications", "id", "oidcconfig", "_changeclientsecret"}, ""))
@ -5998,6 +6126,8 @@ var (
forward_ManagementService_AddProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_ChangeProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_RemoveProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_SearchApplications_0 = runtime.ForwardResponseMessage
@ -6012,6 +6142,8 @@ var (
forward_ManagementService_ReactivateApplication_0 = runtime.ForwardResponseMessage
forward_ManagementService_RemoveApplication_0 = runtime.ForwardResponseMessage
forward_ManagementService_UpdateApplicationOIDCConfig_0 = runtime.ForwardResponseMessage
forward_ManagementService_RegenerateOIDCClientSecret_0 = runtime.ForwardResponseMessage

View File

@ -1318,7 +1318,7 @@
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
"$ref": "#/definitions/v1ProjectRole"
}
}
},
@ -1343,7 +1343,7 @@
]
}
},
"/projects/{id}/roles/{name}": {
"/projects/{id}/roles/{key}": {
"delete": {
"operationId": "RemoveProjectRole",
"responses": {
@ -1362,7 +1362,7 @@
"type": "string"
},
{
"name": "name",
"name": "key",
"in": "path",
"required": true,
"type": "string"
@ -1371,6 +1371,42 @@
"tags": [
"ManagementService"
]
},
"put": {
"operationId": "ChangeProjectRole",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/v1ProjectRole"
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "key",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1ProjectRoleChange"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/projects/{project_id}/applications/_search": {
@ -1473,6 +1509,34 @@
"ManagementService"
]
},
"delete": {
"operationId": "RemoveApplication",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "project_id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
}
],
"tags": [
"ManagementService"
]
},
"put": {
"operationId": "UpdateApplication",
"responses": {
@ -3868,7 +3932,7 @@
"enum": [
"OIDCRESPONSETYPE_CODE",
"OIDCRESPONSETYPE_ID_TOKEN",
"OIDCRESPONSETYPE_TOKEN_ID_TOKEN"
"OIDCRESPONSETYPE_TOKEN"
],
"default": "OIDCRESPONSETYPE_CODE"
},
@ -4898,7 +4962,7 @@
"project_id": {
"type": "string"
},
"name": {
"key": {
"type": "string"
},
"display_name": {
@ -4908,6 +4972,10 @@
"type": "string",
"format": "date-time"
},
"change_date": {
"type": "string",
"format": "date-time"
},
"group": {
"type": "string"
},
@ -4923,7 +4991,24 @@
"id": {
"type": "string"
},
"name": {
"key": {
"type": "string"
},
"display_name": {
"type": "string"
},
"group": {
"type": "string"
}
}
},
"v1ProjectRoleChange": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"key": {
"type": "string"
},
"display_name": {
@ -4938,7 +5023,7 @@
"type": "string",
"enum": [
"PROJECTROLESEARCHKEY_UNSPECIFIED",
"PROJECTROLESEARCHKEY_NAME",
"PROJECTROLESEARCHKEY_KEY",
"PROJECTROLESEARCHKEY_DISPLAY_NAME"
],
"default": "PROJECTROLESEARCHKEY_UNSPECIFIED"

View File

@ -98,14 +98,14 @@ func (mr *MockManagementServiceClientMockRecorder) AddProjectMember(arg0, arg1 i
}
// AddProjectRole mocks base method
func (m *MockManagementServiceClient) AddProjectRole(arg0 context.Context, arg1 *grpc.ProjectRoleAdd, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
func (m *MockManagementServiceClient) AddProjectRole(arg0 context.Context, arg1 *grpc.ProjectRoleAdd, arg2 ...grpc0.CallOption) (*grpc.ProjectRole, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddProjectRole", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret0, _ := ret[0].(*grpc.ProjectRole)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@ -217,6 +217,26 @@ func (mr *MockManagementServiceClientMockRecorder) ChangeProjectMember(arg0, arg
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeProjectMember", reflect.TypeOf((*MockManagementServiceClient)(nil).ChangeProjectMember), varargs...)
}
// ChangeProjectRole mocks base method
func (m *MockManagementServiceClient) ChangeProjectRole(arg0 context.Context, arg1 *grpc.ProjectRoleChange, arg2 ...grpc0.CallOption) (*grpc.ProjectRole, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ChangeProjectRole", varargs...)
ret0, _ := ret[0].(*grpc.ProjectRole)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ChangeProjectRole indicates an expected call of ChangeProjectRole
func (mr *MockManagementServiceClientMockRecorder) ChangeProjectRole(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeProjectRole", reflect.TypeOf((*MockManagementServiceClient)(nil).ChangeProjectRole), varargs...)
}
// ChangeUserEmail mocks base method
func (m *MockManagementServiceClient) ChangeUserEmail(arg0 context.Context, arg1 *grpc.UpdateUserEmailRequest, arg2 ...grpc0.CallOption) (*grpc.UserEmail, error) {
m.ctrl.T.Helper()

View File

@ -51,11 +51,24 @@ func (s *Server) GetGrantedProjectGrantByID(ctx context.Context, request *Grante
return nil, errors.ThrowUnimplemented(nil, "GRPC-974vd", "Not implemented")
}
func (s *Server) AddProjectRole(ctx context.Context, in *ProjectRoleAdd) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-0ow2C", "Not implemented")
func (s *Server) AddProjectRole(ctx context.Context, in *ProjectRoleAdd) (*ProjectRole, error) {
role, err := s.project.AddProjectRole(ctx, projectRoleAddToModel(in))
if err != nil {
return nil, err
}
return projectRoleFromModel(role), nil
}
func (s *Server) ChangeProjectRole(ctx context.Context, in *ProjectRoleChange) (*ProjectRole, error) {
role, err := s.project.ChangeProjectRole(ctx, projectRoleChangeToModel(in))
if err != nil {
return nil, err
}
return projectRoleFromModel(role), nil
}
func (s *Server) RemoveProjectRole(ctx context.Context, in *ProjectRoleRemove) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-bm6iB", "Not implemented")
err := s.project.RemoveProjectRole(ctx, in.Id, in.Key)
return &empty.Empty{}, err
}
func (s *Server) SearchProjectRoles(ctx context.Context, in *ProjectRoleSearchRequest) (*ProjectRoleSearchResponse, error) {

View File

@ -15,7 +15,7 @@ func projectFromModel(project *proj_model.Project) *Project {
logging.Log("GRPC-di7rw").OnError(err).Debug("unable to parse timestamp")
return &Project{
Id: project.ID,
Id: project.AggregateID,
State: projectStateFromModel(project.State),
CreationDate: creationDate,
ChangeDate: changeDate,
@ -26,9 +26,9 @@ func projectFromModel(project *proj_model.Project) *Project {
func projectStateFromModel(state proj_model.ProjectState) ProjectState {
switch state {
case proj_model.Active:
case proj_model.PROJECTSTATE_ACTIVE:
return ProjectState_PROJECTSTATE_ACTIVE
case proj_model.Inactive:
case proj_model.PROJECTSTATE_INACTIVE:
return ProjectState_PROJECTSTATE_INACTIVE
default:
return ProjectState_PROJECTSTATE_UNSPECIFIED
@ -38,8 +38,47 @@ func projectStateFromModel(state proj_model.ProjectState) ProjectState {
func projectUpdateToModel(project *ProjectUpdateRequest) *proj_model.Project {
return &proj_model.Project{
ObjectRoot: models.ObjectRoot{
ID: project.Id,
AggregateID: project.Id,
},
Name: project.Name,
}
}
func projectRoleFromModel(role *proj_model.ProjectRole) *ProjectRole {
creationDate, err := ptypes.TimestampProto(role.CreationDate)
logging.Log("GRPC-due83").OnError(err).Debug("unable to parse timestamp")
changeDate, err := ptypes.TimestampProto(role.ChangeDate)
logging.Log("GRPC-id93s").OnError(err).Debug("unable to parse timestamp")
return &ProjectRole{
CreationDate: creationDate,
ChangeDate: changeDate,
Sequence: role.Sequence,
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}
func projectRoleAddToModel(role *ProjectRoleAdd) *proj_model.ProjectRole {
return &proj_model.ProjectRole{
ObjectRoot: models.ObjectRoot{
AggregateID: role.Id,
},
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}
func projectRoleChangeToModel(role *ProjectRoleChange) *proj_model.ProjectRole {
return &proj_model.ProjectRole{
ObjectRoot: models.ObjectRoot{
AggregateID: role.Id,
},
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}

View File

@ -26,7 +26,7 @@ func projectMemberFromModel(member *proj_model.ProjectMember) *ProjectMember {
func projectMemberAddToModel(member *ProjectMemberAdd) *proj_model.ProjectMember {
return &proj_model.ProjectMember{
ObjectRoot: models.ObjectRoot{
ID: member.Id,
AggregateID: member.Id,
},
UserID: member.UserId,
Roles: member.Roles,
@ -36,7 +36,7 @@ func projectMemberAddToModel(member *ProjectMemberAdd) *proj_model.ProjectMember
func projectMemberChangeToModel(member *ProjectMemberChange) *proj_model.ProjectMember {
return &proj_model.ProjectMember{
ObjectRoot: models.ObjectRoot{
ID: member.Id,
AggregateID: member.Id,
},
UserID: member.UserId,
Roles: member.Roles,

View File

@ -722,7 +722,7 @@ service ManagementService {
};
}
rpc AddProjectRole(ProjectRoleAdd) returns (google.protobuf.Empty) {
rpc AddProjectRole(ProjectRoleAdd) returns (ProjectRole) {
option (google.api.http) = {
post: "/projects/{id}/roles"
body: "*"
@ -734,9 +734,21 @@ service ManagementService {
};
}
rpc ChangeProjectRole(ProjectRoleChange) returns (ProjectRole) {
option (google.api.http) = {
put: "/projects/{id}/roles/{key}"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "project.role.write"
check_field_name: "Id"
};
}
rpc RemoveProjectRole(ProjectRoleRemove) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/projects/{id}/roles/{name}"
delete: "/projects/{id}/roles/{key}"
};
option (caos.zitadel.utils.v1.auth_option) = {
@ -817,6 +829,17 @@ service ManagementService {
};
}
rpc RemoveApplication(ApplicationID) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/projects/{project_id}/applications/{id}"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "project.app.delete"
check_field_name: "ProjectId"
};
}
rpc UpdateApplicationOIDCConfig(OIDCConfigUpdate) returns (OIDCConfig) {
option (google.api.http) = {
put: "/projects/{project_id}/applications/{application_id}/oidcconfig"
@ -1724,24 +1747,32 @@ message ProjectMemberRemove {
}
message ProjectRoleAdd {
string id = 1;
string key = 2;
string display_name = 3;
string group = 4;
}
message ProjectRoleChange {
string id = 1;
string name = 2;
string key = 2;
string display_name = 3;
string group = 4;
}
message ProjectRole {
string project_id = 1;
string name = 2;
string key = 2;
string display_name = 3;
google.protobuf.Timestamp creation_date = 4;
string group = 5;
uint64 sequence = 6;
google.protobuf.Timestamp change_date = 5;
string group = 6;
uint64 sequence = 7;
}
message ProjectRoleRemove {
string id = 1;
string name = 2;
string key = 2;
}
message ProjectRoleSearchResponse {
@ -1766,7 +1797,7 @@ message ProjectRoleSearchQuery {
enum ProjectRoleSearchKey {
PROJECTROLESEARCHKEY_UNSPECIFIED = 0;
PROJECTROLESEARCHKEY_NAME = 1;
PROJECTROLESEARCHKEY_KEY = 1;
PROJECTROLESEARCHKEY_DISPLAY_NAME = 2;
}
@ -1859,7 +1890,7 @@ message OIDCConfigUpdate {
enum OIDCResponseType {
OIDCRESPONSETYPE_CODE = 0;
OIDCRESPONSETYPE_ID_TOKEN = 1;
OIDCRESPONSETYPE_TOKEN_ID_TOKEN = 2;
OIDCRESPONSETYPE_TOKEN = 2;
}
enum OIDCGrantType {