mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:17:32 +00:00
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:
47
internal/project/model/application.go
Normal file
47
internal/project/model/application.go
Normal 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
|
||||
}
|
170
internal/project/model/application_test.go
Normal file
170
internal/project/model/application_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
88
internal/project/model/oidc_config.go
Normal file
88
internal/project/model/oidc_config.go
Normal 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
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
19
internal/project/model/project_role.go
Normal file
19
internal/project/model/project_role.go
Normal 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 != ""
|
||||
}
|
@@ -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)
|
||||
}
|
@@ -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"
|
||||
|
||||
|
Reference in New Issue
Block a user