mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 01:37:31 +00:00
feat: idp and login policy configurations (#619)
* feat: oidc config * fix: oidc configurations * feat: oidc idp config * feat: add oidc config test * fix: tests * fix: tests * feat: translate new events * feat: idp eventstore * feat: idp eventstore * fix: tests * feat: command side idp * feat: query side idp * feat: idp config on org * fix: tests * feat: authz idp on org * feat: org idps * feat: login policy * feat: login policy * feat: login policy * feat: add idp func on login policy * feat: add validation to loginpolicy and idp provider * feat: add default login policy * feat: login policy on org * feat: login policy on org * fix: id config handlers * fix: id config handlers * fix: create idp on org * fix: create idp on org * fix: not existing idp config * fix: default login policy * fix: add login policy on org * fix: idp provider search on org * fix: test * fix: remove idp on org * fix: test * fix: test * fix: remove admin idp * fix: logo src as byte * fix: migration * fix: tests * Update internal/iam/repository/eventsourcing/iam.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/iam_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/iam_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/org/repository/eventsourcing/org_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/iam/repository/eventsourcing/model/login_policy_test.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: pr comments * fix: tests * Update types.go * fix: merge request changes * fix: reduce optimization Co-authored-by: Silvan <silvan.reusser@gmail.com> Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -4,16 +4,18 @@ import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type Iam struct {
|
||||
type IAM struct {
|
||||
es_models.ObjectRoot
|
||||
GlobalOrgID string
|
||||
IamProjectID string
|
||||
SetUpDone bool
|
||||
SetUpStarted bool
|
||||
Members []*IamMember
|
||||
GlobalOrgID string
|
||||
IAMProjectID string
|
||||
SetUpDone bool
|
||||
SetUpStarted bool
|
||||
Members []*IAMMember
|
||||
IDPs []*IDPConfig
|
||||
DefaultLoginPolicy *LoginPolicy
|
||||
}
|
||||
|
||||
func (iam *Iam) GetMember(userID string) (int, *IamMember) {
|
||||
func (iam *IAM) GetMember(userID string) (int, *IAMMember) {
|
||||
for i, m := range iam.Members {
|
||||
if m.UserID == userID {
|
||||
return i, m
|
||||
@@ -21,3 +23,12 @@ func (iam *Iam) GetMember(userID string) (int, *IamMember) {
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
func (iam *IAM) GetIDP(idpID string) (int, *IDPConfig) {
|
||||
for i, idp := range iam.IDPs {
|
||||
if idp.IDPConfigID == idpID {
|
||||
return i, idp
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
@@ -2,17 +2,17 @@ package model
|
||||
|
||||
import es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
type IamMember struct {
|
||||
type IAMMember struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
UserID string
|
||||
Roles []string
|
||||
}
|
||||
|
||||
func NewIamMember(iamID, userID string) *IamMember {
|
||||
return &IamMember{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, UserID: userID}
|
||||
func NewIAMMember(iamID, userID string) *IAMMember {
|
||||
return &IAMMember{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, UserID: userID}
|
||||
}
|
||||
|
||||
func (i *IamMember) IsValid() bool {
|
||||
func (i *IAMMember) IsValid() bool {
|
||||
return i.AggregateID != "" && i.UserID != "" && len(i.Roles) != 0
|
||||
}
|
||||
|
@@ -5,9 +5,9 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type IamMemberView struct {
|
||||
type IAMMemberView struct {
|
||||
UserID string
|
||||
IamID string
|
||||
IAMID string
|
||||
UserName string
|
||||
Email string
|
||||
FirstName string
|
||||
@@ -19,42 +19,42 @@ type IamMemberView struct {
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type IamMemberSearchRequest struct {
|
||||
type IAMMemberSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn IamMemberSearchKey
|
||||
SortingColumn IAMMemberSearchKey
|
||||
Asc bool
|
||||
Queries []*IamMemberSearchQuery
|
||||
Queries []*IAMMemberSearchQuery
|
||||
}
|
||||
|
||||
type IamMemberSearchKey int32
|
||||
type IAMMemberSearchKey int32
|
||||
|
||||
const (
|
||||
IamMemberSearchKeyUnspecified IamMemberSearchKey = iota
|
||||
IamMemberSearchKeyUserName
|
||||
IamMemberSearchKeyEmail
|
||||
IamMemberSearchKeyFirstName
|
||||
IamMemberSearchKeyLastName
|
||||
IamMemberSearchKeyIamID
|
||||
IamMemberSearchKeyUserID
|
||||
IAMMemberSearchKeyUnspecified IAMMemberSearchKey = iota
|
||||
IAMMemberSearchKeyUserName
|
||||
IAMMemberSearchKeyEmail
|
||||
IAMMemberSearchKeyFirstName
|
||||
IAMMemberSearchKeyLastName
|
||||
IAMMemberSearchKeyIamID
|
||||
IAMMemberSearchKeyUserID
|
||||
)
|
||||
|
||||
type IamMemberSearchQuery struct {
|
||||
Key IamMemberSearchKey
|
||||
type IAMMemberSearchQuery struct {
|
||||
Key IAMMemberSearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type IamMemberSearchResponse struct {
|
||||
type IAMMemberSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*IamMemberView
|
||||
Result []*IAMMemberView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (r *IamMemberSearchRequest) EnsureLimit(limit uint64) {
|
||||
func (r *IAMMemberSearchRequest) EnsureLimit(limit uint64) {
|
||||
if r.Limit == 0 || r.Limit > limit {
|
||||
r.Limit = limit
|
||||
}
|
||||
|
74
internal/iam/model/idp_config.go
Normal file
74
internal/iam/model/idp_config.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type IDPConfig struct {
|
||||
es_models.ObjectRoot
|
||||
IDPConfigID string
|
||||
Type IdpConfigType
|
||||
Name string
|
||||
LogoSrc []byte
|
||||
State IDPConfigState
|
||||
OIDCConfig *OIDCIDPConfig
|
||||
}
|
||||
|
||||
type OIDCIDPConfig struct {
|
||||
es_models.ObjectRoot
|
||||
IDPConfigID string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
ClientSecretString string
|
||||
Issuer string
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
type IdpConfigType int32
|
||||
|
||||
const (
|
||||
IDPConfigTypeOIDC IdpConfigType = iota
|
||||
IDPConfigTypeSAML
|
||||
)
|
||||
|
||||
type IDPConfigState int32
|
||||
|
||||
const (
|
||||
IDPConfigStateActive IDPConfigState = iota
|
||||
IDPConfigStateInactive
|
||||
IDPConfigStateRemoved
|
||||
)
|
||||
|
||||
func NewIDPConfig(iamID, idpID string) *IDPConfig {
|
||||
return &IDPConfig{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, IDPConfigID: idpID}
|
||||
}
|
||||
|
||||
func (idp *IDPConfig) IsValid(includeConfig bool) bool {
|
||||
if idp.Name == "" || idp.AggregateID == "" {
|
||||
return false
|
||||
}
|
||||
if !includeConfig {
|
||||
return true
|
||||
}
|
||||
if idp.Type == IDPConfigTypeOIDC && !idp.OIDCConfig.IsValid(true) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (oi *OIDCIDPConfig) IsValid(withSecret bool) bool {
|
||||
if withSecret {
|
||||
return oi.ClientID != "" && oi.Issuer != "" && oi.ClientSecretString != ""
|
||||
}
|
||||
return oi.ClientID != "" && oi.Issuer != ""
|
||||
}
|
||||
|
||||
func (oi *OIDCIDPConfig) CryptSecret(crypt crypto.Crypto) error {
|
||||
cryptedSecret, err := crypto.Crypt([]byte(oi.ClientSecretString), crypt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oi.ClientSecret = cryptedSecret
|
||||
return nil
|
||||
}
|
68
internal/iam/model/idp_config_view.go
Normal file
68
internal/iam/model/idp_config_view.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IDPConfigView struct {
|
||||
AggregateID string
|
||||
IDPConfigID string
|
||||
Name string
|
||||
LogoSrc []byte
|
||||
State IDPConfigState
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
IDPProviderType IDPProviderType
|
||||
|
||||
IsOIDC bool
|
||||
OIDCClientID string
|
||||
OIDCClientSecret *crypto.CryptoValue
|
||||
OIDCIssuer string
|
||||
OIDCScopes []string
|
||||
}
|
||||
|
||||
type IDPConfigSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn IDPConfigSearchKey
|
||||
Asc bool
|
||||
Queries []*IDPConfigSearchQuery
|
||||
}
|
||||
|
||||
type IDPConfigSearchKey int32
|
||||
|
||||
const (
|
||||
IDPConfigSearchKeyUnspecified IDPConfigSearchKey = iota
|
||||
IDPConfigSearchKeyName
|
||||
IDPConfigSearchKeyAggregateID
|
||||
IDPConfigSearchKeyIdpConfigID
|
||||
IDPConfigSearchKeyIdpProviderType
|
||||
)
|
||||
|
||||
type IDPConfigSearchQuery struct {
|
||||
Key IDPConfigSearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type IDPConfigSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*IDPConfigView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (r *IDPConfigSearchRequest) EnsureLimit(limit uint64) {
|
||||
if r.Limit == 0 || r.Limit > limit {
|
||||
r.Limit = limit
|
||||
}
|
||||
}
|
||||
|
||||
func (r *IDPConfigSearchRequest) AppendMyOrgQuery(orgID, iamID string) {
|
||||
r.Queries = append(r.Queries, &IDPConfigSearchQuery{Key: IDPConfigSearchKeyAggregateID, Method: model.SearchMethodIsOneOf, Value: []string{orgID, iamID}})
|
||||
}
|
59
internal/iam/model/idp_provider_view.go
Normal file
59
internal/iam/model/idp_provider_view.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IDPProviderView struct {
|
||||
AggregateID string
|
||||
IDPConfigID string
|
||||
IDPProviderType IDPProviderType
|
||||
Name string
|
||||
IDPConfigType IdpConfigType
|
||||
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type IDPProviderSearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn IDPProviderSearchKey
|
||||
Asc bool
|
||||
Queries []*IDPProviderSearchQuery
|
||||
}
|
||||
|
||||
type IDPProviderSearchKey int32
|
||||
|
||||
const (
|
||||
IDPProviderSearchKeyUnspecified IDPProviderSearchKey = iota
|
||||
IDPProviderSearchKeyAggregateID
|
||||
IDPProviderSearchKeyIdpConfigID
|
||||
)
|
||||
|
||||
type IDPProviderSearchQuery struct {
|
||||
Key IDPProviderSearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type IDPProviderSearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*IDPProviderView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (r *IDPProviderSearchRequest) EnsureLimit(limit uint64) {
|
||||
if r.Limit == 0 || r.Limit > limit {
|
||||
r.Limit = limit
|
||||
}
|
||||
}
|
||||
|
||||
func (r *IDPProviderSearchRequest) AppendAggregateIDQuery(aggregateID string) {
|
||||
r.Queries = append(r.Queries, &IDPProviderSearchQuery{Key: IDPProviderSearchKeyAggregateID, Method: model.SearchMethodEquals, Value: aggregateID})
|
||||
}
|
53
internal/iam/model/login_policy.go
Normal file
53
internal/iam/model/login_policy.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type LoginPolicy struct {
|
||||
models.ObjectRoot
|
||||
|
||||
State PolicyState
|
||||
Default bool
|
||||
AllowUsernamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIdp bool
|
||||
IDPProviders []*IDPProvider
|
||||
}
|
||||
|
||||
type IDPProvider struct {
|
||||
models.ObjectRoot
|
||||
Type IDPProviderType
|
||||
IdpConfigID string
|
||||
}
|
||||
|
||||
type PolicyState int32
|
||||
|
||||
const (
|
||||
PolicyStateActive PolicyState = iota
|
||||
PolicyStateRemoved
|
||||
)
|
||||
|
||||
type IDPProviderType int32
|
||||
|
||||
const (
|
||||
IDPProviderTypeSystem IDPProviderType = iota
|
||||
IDPProviderTypeOrg
|
||||
)
|
||||
|
||||
func (p *LoginPolicy) IsValid() bool {
|
||||
return p.ObjectRoot.AggregateID != ""
|
||||
}
|
||||
|
||||
func (p *IDPProvider) IsValid() bool {
|
||||
return p.ObjectRoot.AggregateID != "" && p.IdpConfigID != ""
|
||||
}
|
||||
|
||||
func (p *LoginPolicy) GetIdpProvider(id string) (int, *IDPProvider) {
|
||||
for i, m := range p.IDPProviders {
|
||||
if m.IdpConfigID == id {
|
||||
return i, m
|
||||
}
|
||||
}
|
||||
return -1, nil
|
||||
}
|
48
internal/iam/model/login_policy_view.go
Normal file
48
internal/iam/model/login_policy_view.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LoginPolicyView struct {
|
||||
AggregateID string
|
||||
AllowUsernamePassword bool
|
||||
AllowRegister bool
|
||||
AllowExternalIDP bool
|
||||
Default bool
|
||||
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type LoginPolicySearchRequest struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
SortingColumn LoginPolicySearchKey
|
||||
Asc bool
|
||||
Queries []*LoginPolicySearchQuery
|
||||
}
|
||||
|
||||
type LoginPolicySearchKey int32
|
||||
|
||||
const (
|
||||
LoginPolicySearchKeyUnspecified LoginPolicySearchKey = iota
|
||||
LoginPolicySearchKeyAggregateID
|
||||
)
|
||||
|
||||
type LoginPolicySearchQuery struct {
|
||||
Key LoginPolicySearchKey
|
||||
Method model.SearchMethod
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type LoginPolicySearchResponse struct {
|
||||
Offset uint64
|
||||
Limit uint64
|
||||
TotalResult uint64
|
||||
Result []*LoginPolicyView
|
||||
Sequence uint64
|
||||
Timestamp time.Time
|
||||
}
|
Reference in New Issue
Block a user