mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:57:24 +00:00
feat(api): add google provider template (#5247)
add functionality to manage templates based Google IDP
This commit is contained in:
parent
94116fa04b
commit
40e7356f3e
@ -593,12 +593,36 @@ Returns an identity provider of the instance
|
||||
GET: /idps/templates/{id}
|
||||
|
||||
|
||||
### AddGoogleProvider
|
||||
|
||||
> **rpc** AddGoogleProvider([AddGoogleProviderRequest](#addgoogleproviderrequest))
|
||||
[AddGoogleProviderResponse](#addgoogleproviderresponse)
|
||||
|
||||
Add a new Google identity provider on the instance
|
||||
|
||||
|
||||
|
||||
POST: /idps/google
|
||||
|
||||
|
||||
### UpdateGoogleProvider
|
||||
|
||||
> **rpc** UpdateGoogleProvider([UpdateGoogleProviderRequest](#updategoogleproviderrequest))
|
||||
[UpdateGoogleProviderResponse](#updategoogleproviderresponse)
|
||||
|
||||
Change an existing Google identity provider on the instance
|
||||
|
||||
|
||||
|
||||
PUT: /idps/google/{id}
|
||||
|
||||
|
||||
### AddLDAPProvider
|
||||
|
||||
> **rpc** AddLDAPProvider([AddLDAPProviderRequest](#addldapproviderrequest))
|
||||
[AddLDAPProviderResponse](#addldapproviderresponse)
|
||||
|
||||
Add a new ldap identity provider on the instance
|
||||
Add a new LDAP identity provider on the instance
|
||||
|
||||
|
||||
|
||||
@ -610,7 +634,7 @@ Add a new ldap identity provider on the instance
|
||||
> **rpc** UpdateLDAPProvider([UpdateLDAPProviderRequest](#updateldapproviderrequest))
|
||||
[UpdateLDAPProviderResponse](#updateldapproviderresponse)
|
||||
|
||||
Change an existing ldap identity provider on the instance
|
||||
Change an existing LDAP identity provider on the instance
|
||||
|
||||
|
||||
|
||||
@ -1849,6 +1873,33 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### AddGoogleProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| name | string | Google will be used as default, if no name is provided | string.max_len: 200<br /> |
|
||||
| client_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| client_secret | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| scopes | repeated string | - | repeated.max_items: 20<br /> repeated.items.string.min_len: 1<br /> repeated.items.string.max_len: 100<br /> |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddGoogleProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
| id | string | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddIAMMemberRequest
|
||||
|
||||
|
||||
@ -4788,6 +4839,33 @@ this is en empty request
|
||||
|
||||
|
||||
|
||||
### UpdateGoogleProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| name | string | - | string.max_len: 200<br /> |
|
||||
| client_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| client_secret | string | client_secret will only be updated if provided | string.max_len: 200<br /> |
|
||||
| scopes | repeated string | - | repeated.max_items: 20<br /> repeated.items.string.min_len: 1<br /> repeated.items.string.max_len: 100<br /> |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateGoogleProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateIAMMemberRequest
|
||||
|
||||
|
||||
|
@ -9,6 +9,18 @@ title: zitadel/idp.proto
|
||||
## Messages
|
||||
|
||||
|
||||
### GoogleConfig
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| client_id | string | - | |
|
||||
| scopes | repeated string | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### IDP
|
||||
|
||||
|
||||
@ -201,6 +213,7 @@ title: zitadel/idp.proto
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| options | Options | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.ldap | LDAPConfig | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.google | GoogleConfig | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -3050,12 +3050,36 @@ Returns an identity provider of the organisation
|
||||
GET: /idps/templates/{id}
|
||||
|
||||
|
||||
### AddGoogleProvider
|
||||
|
||||
> **rpc** AddGoogleProvider([AddGoogleProviderRequest](#addgoogleproviderrequest))
|
||||
[AddGoogleProviderResponse](#addgoogleproviderresponse)
|
||||
|
||||
Add a new Google identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
POST: /idps/google
|
||||
|
||||
|
||||
### UpdateGoogleProvider
|
||||
|
||||
> **rpc** UpdateGoogleProvider([UpdateGoogleProviderRequest](#updategoogleproviderrequest))
|
||||
[UpdateGoogleProviderResponse](#updategoogleproviderresponse)
|
||||
|
||||
Change an existing Google identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
PUT: /idps/google/{id}
|
||||
|
||||
|
||||
### AddLDAPProvider
|
||||
|
||||
> **rpc** AddLDAPProvider([AddLDAPProviderRequest](#addldapproviderrequest))
|
||||
[AddLDAPProviderResponse](#addldapproviderresponse)
|
||||
|
||||
Add a new ldap identity provider in the organisation
|
||||
Add a new LDAP identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
@ -3067,7 +3091,7 @@ Add a new ldap identity provider in the organisation
|
||||
> **rpc** UpdateLDAPProvider([UpdateLDAPProviderRequest](#updateldapproviderrequest))
|
||||
[UpdateLDAPProviderResponse](#updateldapproviderresponse)
|
||||
|
||||
Change an existing ldap identity provider in the organisation
|
||||
Change an existing LDAP identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
@ -3523,6 +3547,33 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### AddGoogleProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| name | string | Google will be used as default, if no name is provided | string.max_len: 200<br /> |
|
||||
| client_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| client_secret | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| scopes | repeated string | - | repeated.max_items: 20<br /> repeated.items.string.min_len: 1<br /> repeated.items.string.max_len: 100<br /> |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddGoogleProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
| id | string | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddHumanUserRequest
|
||||
|
||||
|
||||
@ -8860,6 +8911,33 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### UpdateGoogleProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| name | string | - | string.max_len: 200<br /> |
|
||||
| client_id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| client_secret | string | client_secret will only be updated if provided | string.max_len: 200<br /> |
|
||||
| scopes | repeated string | - | repeated.max_items: 20<br /> repeated.items.string.min_len: 1<br /> repeated.items.string.max_len: 100<br /> |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateGoogleProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateHumanEmailRequest
|
||||
|
||||
|
||||
|
@ -174,6 +174,27 @@ func (s *Server) ListProviders(ctx context.Context, req *admin_pb.ListProvidersR
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddGoogleProvider(ctx context.Context, req *admin_pb.AddGoogleProviderRequest) (*admin_pb.AddGoogleProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, addGoogleProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.AddGoogleProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateGoogleProvider(ctx context.Context, req *admin_pb.UpdateGoogleProviderRequest) (*admin_pb.UpdateGoogleProviderResponse, error) {
|
||||
details, err := s.command.UpdateOrgGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateGoogleProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.UpdateGoogleProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddLDAPProvider(ctx context.Context, req *admin_pb.AddLDAPProviderRequest) (*admin_pb.AddLDAPProviderResponse, error) {
|
||||
id, details, err := s.command.AddInstanceLDAPProvider(ctx, addLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
|
@ -201,6 +201,26 @@ func providerQueryToQuery(idpQuery *admin_pb.ProviderQuery) (query.SearchQuery,
|
||||
}
|
||||
}
|
||||
|
||||
func addGoogleProviderToCommand(req *admin_pb.AddGoogleProviderRequest) command.GoogleProvider {
|
||||
return command.GoogleProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateGoogleProviderToCommand(req *admin_pb.UpdateGoogleProviderRequest) command.GoogleProvider {
|
||||
return command.GoogleProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func addLDAPProviderToCommand(req *admin_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
|
@ -402,6 +402,14 @@ func configToPb(config *query.IDPTemplate) *idp_pb.ProviderConfig {
|
||||
IsAutoUpdate: config.IsAutoUpdate,
|
||||
},
|
||||
}
|
||||
if config.GoogleIDPTemplate != nil {
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Google{
|
||||
Google: &idp_pb.GoogleConfig{
|
||||
ClientId: config.GoogleIDPTemplate.ClientID,
|
||||
Scopes: config.GoogleIDPTemplate.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
if config.LDAPIDPTemplate != nil {
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Ldap{
|
||||
Ldap: &idp_pb.LDAPConfig{
|
||||
|
@ -166,6 +166,27 @@ func (s *Server) ListProviders(ctx context.Context, req *mgmt_pb.ListProvidersRe
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddGoogleProvider(ctx context.Context, req *mgmt_pb.AddGoogleProviderRequest) (*mgmt_pb.AddGoogleProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, addGoogleProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddGoogleProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateGoogleProvider(ctx context.Context, req *mgmt_pb.UpdateGoogleProviderRequest) (*mgmt_pb.UpdateGoogleProviderResponse, error) {
|
||||
details, err := s.command.UpdateOrgGoogleProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateGoogleProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateGoogleProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddLDAPProvider(ctx context.Context, req *mgmt_pb.AddLDAPProviderRequest) (*mgmt_pb.AddLDAPProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgLDAPProvider(ctx, authz.GetCtxData(ctx).OrgID, addLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
|
@ -218,6 +218,26 @@ func providerQueryToQuery(idpQuery *mgmt_pb.ProviderQuery) (query.SearchQuery, e
|
||||
}
|
||||
}
|
||||
|
||||
func addGoogleProviderToCommand(req *mgmt_pb.AddGoogleProviderRequest) command.GoogleProvider {
|
||||
return command.GoogleProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateGoogleProviderToCommand(req *mgmt_pb.UpdateGoogleProviderRequest) command.GoogleProvider {
|
||||
return command.GoogleProvider{
|
||||
Name: req.Name,
|
||||
ClientID: req.ClientId,
|
||||
ClientSecret: req.ClientSecret,
|
||||
Scopes: req.Scopes,
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func addLDAPProviderToCommand(req *mgmt_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
|
@ -2,6 +2,14 @@ package command
|
||||
|
||||
import "github.com/zitadel/zitadel/internal/repository/idp"
|
||||
|
||||
type GoogleProvider struct {
|
||||
Name string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
Scopes []string
|
||||
IDPOptions idp.Options
|
||||
}
|
||||
|
||||
type LDAPProvider struct {
|
||||
Name string
|
||||
Host string
|
||||
|
@ -1,6 +1,8 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -8,6 +10,93 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type GoogleIDPWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
Name string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
Scopes []string
|
||||
idp.Options
|
||||
|
||||
State domain.IDPState
|
||||
}
|
||||
|
||||
func (wm *GoogleIDPWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.GoogleIDPAddedEvent:
|
||||
wm.reduceAddedEvent(e)
|
||||
case *idp.GoogleIDPChangedEvent:
|
||||
wm.reduceChangedEvent(e)
|
||||
case *idp.RemovedEvent:
|
||||
wm.State = domain.IDPStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *GoogleIDPWriteModel) reduceAddedEvent(e *idp.GoogleIDPAddedEvent) {
|
||||
wm.Name = e.Name
|
||||
wm.ClientID = e.ClientID
|
||||
wm.ClientSecret = e.ClientSecret
|
||||
wm.Scopes = e.Scopes
|
||||
wm.Options = e.Options
|
||||
wm.State = domain.IDPStateActive
|
||||
}
|
||||
|
||||
func (wm *GoogleIDPWriteModel) reduceChangedEvent(e *idp.GoogleIDPChangedEvent) {
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.ClientID != nil {
|
||||
wm.ClientID = *e.ClientID
|
||||
}
|
||||
if e.ClientSecret != nil {
|
||||
wm.ClientSecret = e.ClientSecret
|
||||
}
|
||||
if e.Scopes != nil {
|
||||
wm.Scopes = e.Scopes
|
||||
}
|
||||
wm.Options.ReduceChanges(e.OptionChanges)
|
||||
}
|
||||
|
||||
func (wm *GoogleIDPWriteModel) NewChanges(
|
||||
name string,
|
||||
clientID string,
|
||||
clientSecretString string,
|
||||
secretCrypto crypto.Crypto,
|
||||
scopes []string,
|
||||
options idp.Options,
|
||||
) ([]idp.GoogleIDPChanges, error) {
|
||||
changes := make([]idp.GoogleIDPChanges, 0)
|
||||
var clientSecret *crypto.CryptoValue
|
||||
var err error
|
||||
if clientSecretString != "" {
|
||||
clientSecret, err = crypto.Crypt([]byte(clientSecretString), secretCrypto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes = append(changes, idp.ChangeGoogleClientSecret(clientSecret))
|
||||
}
|
||||
if wm.Name != name {
|
||||
changes = append(changes, idp.ChangeGoogleName(name))
|
||||
}
|
||||
if wm.ClientID != clientID {
|
||||
changes = append(changes, idp.ChangeGoogleClientID(clientID))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.Scopes, scopes) {
|
||||
changes = append(changes, idp.ChangeGoogleScopes(scopes))
|
||||
}
|
||||
|
||||
opts := wm.Options.Changes(options)
|
||||
if !opts.IsZero() {
|
||||
changes = append(changes, idp.ChangeGoogleOptions(opts))
|
||||
}
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
type LDAPIDPWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
@ -34,7 +123,7 @@ func (wm *LDAPIDPWriteModel) Reduce() error {
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.reduceAddeddEvent(e)
|
||||
wm.reduceAddedEvent(e)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
@ -50,7 +139,7 @@ func (wm *LDAPIDPWriteModel) Reduce() error {
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceAddeddEvent(e *idp.LDAPIDPAddedEvent) {
|
||||
func (wm *LDAPIDPWriteModel) reduceAddedEvent(e *idp.LDAPIDPAddedEvent) {
|
||||
wm.Name = e.Name
|
||||
wm.Host = e.Host
|
||||
wm.Port = e.Port
|
||||
@ -170,6 +259,10 @@ type IDPRemoveWriteModel struct {
|
||||
func (wm *IDPRemoveWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.GoogleIDPAddedEvent:
|
||||
wm.reduceAdded(e.ID, e.Name)
|
||||
case *idp.GoogleIDPChangedEvent:
|
||||
wm.reduceChanged(e.ID, e.Name)
|
||||
case *idp.LDAPIDPAddedEvent:
|
||||
wm.reduceAdded(e.ID, e.Name)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
|
@ -13,6 +13,40 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func (c *Commands) AddInstanceGoogleProvider(ctx context.Context, provider GoogleProvider) (string, *domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddInstanceGoogleProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateInstanceGoogleProvider(ctx context.Context, id string, provider GoogleProvider) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateInstanceGoogleProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddInstanceLDAPProvider(ctx context.Context, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
id, err := c.idGenerator.Next()
|
||||
@ -60,6 +94,87 @@ func (c *Commands) DeleteInstanceProvider(ctx context.Context, id string) (*doma
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddInstanceGoogleProvider(a *instance.Aggregate, id string, provider GoogleProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-D3fvs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-W2vqs", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewGoogleInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
instance.NewGoogleIDPAddedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.ClientID,
|
||||
secret,
|
||||
provider.Scopes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateInstanceGoogleProvider(a *instance.Aggregate, id string, provider GoogleProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-S32t1", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-ds432", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewGoogleInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "INST-D3r1s", "Errors.Instance.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.ClientID,
|
||||
provider.ClientSecret,
|
||||
c.idpConfigEncryption,
|
||||
provider.Scopes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
|
@ -9,6 +9,80 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
type InstanceGoogleIDPWriteModel struct {
|
||||
GoogleIDPWriteModel
|
||||
}
|
||||
|
||||
func NewGoogleInstanceIDPWriteModel(instanceID, id string) *InstanceGoogleIDPWriteModel {
|
||||
return &InstanceGoogleIDPWriteModel{
|
||||
GoogleIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceGoogleIDPWriteModel) Reduce() error {
|
||||
return wm.GoogleIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceGoogleIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.GoogleIDPAddedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
|
||||
case *instance.GoogleIDPChangedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
|
||||
case *instance.IDPRemovedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceGoogleIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.GoogleIDPAddedEventType,
|
||||
instance.GoogleIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
).
|
||||
EventData(map[string]interface{}{"id": wm.ID}).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *InstanceGoogleIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
clientID,
|
||||
clientSecretString string,
|
||||
secretCrypto crypto.Crypto,
|
||||
scopes []string,
|
||||
options idp.Options,
|
||||
) (*instance.GoogleIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.GoogleIDPWriteModel.NewChanges(name, clientID, clientSecretString, secretCrypto, scopes, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := instance.NewGoogleIDPChangedEvent(ctx, aggregate, id, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type InstanceLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
@ -136,6 +210,10 @@ func (wm *InstanceIDPRemoveWriteModel) Reduce() error {
|
||||
func (wm *InstanceIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.GoogleIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
|
||||
case *instance.GoogleIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
@ -155,6 +233,8 @@ func (wm *InstanceIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.GoogleIDPAddedEventType,
|
||||
instance.GoogleIDPChangedEventType,
|
||||
instance.LDAPIDPAddedEventType,
|
||||
instance.LDAPIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
|
@ -20,6 +20,363 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddInstanceGoogleIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
provider GoogleProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid clientID",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid clientSecret",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
},
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
[]string{"openid"},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
},
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
Scopes: []string{"openid"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddInstanceGoogleProvider(tt.args.ctx, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateInstanceGoogleIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
id string
|
||||
provider GoogleProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid clientID",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewGoogleIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := instance.NewGoogleIDPChangedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
[]idp.GoogleIDPChanges{
|
||||
idp.ChangeGoogleClientID("clientID2"),
|
||||
idp.ChangeGoogleClientSecret(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newSecret"),
|
||||
}),
|
||||
idp.ChangeGoogleScopes([]string{"openid", "profile"}),
|
||||
idp.ChangeGoogleOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID2",
|
||||
ClientSecret: "newSecret",
|
||||
Scopes: []string{"openid", "profile"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateInstanceGoogleProvider(tt.args.ctx, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
|
@ -12,6 +12,40 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) AddOrgGoogleProvider(ctx context.Context, resourceOwner string, provider GoogleProvider) (string, *domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddOrgGoogleProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateOrgGoogleProvider(ctx context.Context, resourceOwner, id string, provider GoogleProvider) (*domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateOrgGoogleProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) AddOrgLDAPProvider(ctx context.Context, resourceOwner string, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
id, err := c.idGenerator.Next()
|
||||
@ -59,6 +93,78 @@ func (c *Commands) DeleteOrgProvider(ctx context.Context, resourceOwner, id stri
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddOrgGoogleProvider(a *org.Aggregate, resourceOwner, id string, provider GoogleProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-D3fvs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.ClientSecret = strings.TrimSpace(provider.ClientSecret); provider.ClientSecret == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-W2vqs", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewGoogleOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.ClientSecret), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
org.NewGoogleIDPAddedEvent(ctx, &a.Aggregate, id, provider.Name, provider.ClientID, secret, provider.Scopes, provider.IDPOptions),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateOrgGoogleProvider(a *org.Aggregate, resourceOwner, id string, provider GoogleProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-S32t1", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.ClientID = strings.TrimSpace(provider.ClientID); provider.ClientID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-ds432", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewGoogleOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-Dqrg1", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.ClientID,
|
||||
provider.ClientSecret,
|
||||
c.idpConfigEncryption,
|
||||
provider.Scopes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, resourceOwner, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
|
@ -9,6 +9,82 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type OrgGoogleIDPWriteModel struct {
|
||||
GoogleIDPWriteModel
|
||||
}
|
||||
|
||||
func NewGoogleOrgIDPWriteModel(orgID, id string) *OrgGoogleIDPWriteModel {
|
||||
return &OrgGoogleIDPWriteModel{
|
||||
GoogleIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgGoogleIDPWriteModel) Reduce() error {
|
||||
return wm.GoogleIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgGoogleIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.GoogleIDPAddedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
|
||||
case *org.GoogleIDPChangedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
|
||||
case *org.IDPRemovedEvent:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.GoogleIDPWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgGoogleIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.GoogleIDPAddedEventType,
|
||||
org.GoogleIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
).
|
||||
EventData(map[string]interface{}{"id": wm.ID}).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *OrgGoogleIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
clientID,
|
||||
clientSecretString string,
|
||||
secretCrypto crypto.Crypto,
|
||||
scopes []string,
|
||||
options idp.Options,
|
||||
) (*org.GoogleIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.GoogleIDPWriteModel.NewChanges(name, clientID, clientSecretString, secretCrypto, scopes, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := org.NewGoogleIDPChangedEvent(ctx, aggregate, id, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type OrgLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
@ -136,6 +212,10 @@ func (wm *OrgIDPRemoveWriteModel) Reduce() error {
|
||||
func (wm *OrgIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.GoogleIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.GoogleIDPAddedEvent)
|
||||
case *org.GoogleIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.GoogleIDPChangedEvent)
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
@ -155,6 +235,8 @@ func (wm *OrgIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.GoogleIDPAddedEventType,
|
||||
org.GoogleIDPChangedEventType,
|
||||
org.LDAPIDPAddedEventType,
|
||||
org.LDAPIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
|
@ -18,6 +18,365 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddOrgGoogleIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
provider GoogleProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid clientID",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid clientSecret",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
[]string{"openid"},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
Scopes: []string{"openid"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddOrgGoogleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateOrgGoogleIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
id string
|
||||
provider GoogleProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid clientID",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: GoogleProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewGoogleIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"",
|
||||
"clientID",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("clientSecret"),
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := org.NewGoogleIDPChangedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
[]idp.GoogleIDPChanges{
|
||||
idp.ChangeGoogleClientID("clientID2"),
|
||||
idp.ChangeGoogleClientSecret(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newSecret"),
|
||||
}),
|
||||
idp.ChangeGoogleScopes([]string{"openid", "profile"}),
|
||||
idp.ChangeGoogleOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: GoogleProvider{
|
||||
ClientID: "clientID2",
|
||||
ClientSecret: "newSecret",
|
||||
Scopes: []string{"openid", "profile"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateOrgGoogleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
@ -32,6 +33,7 @@ type IDPTemplate struct {
|
||||
IsLinkingAllowed bool
|
||||
IsAutoCreation bool
|
||||
IsAutoUpdate bool
|
||||
*GoogleIDPTemplate
|
||||
*LDAPIDPTemplate
|
||||
}
|
||||
|
||||
@ -40,6 +42,13 @@ type IDPTemplates struct {
|
||||
Templates []*IDPTemplate
|
||||
}
|
||||
|
||||
type GoogleIDPTemplate struct {
|
||||
IDPID string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
Scopes database.StringArray
|
||||
}
|
||||
|
||||
type LDAPIDPTemplate struct {
|
||||
IDPID string
|
||||
Host string
|
||||
@ -51,7 +60,6 @@ type LDAPIDPTemplate struct {
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
idp.LDAPAttributes
|
||||
idp.Options
|
||||
}
|
||||
|
||||
var (
|
||||
@ -121,6 +129,33 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
googleIdpTemplateTable = table{
|
||||
name: projection.IDPTemplateGoogleTable,
|
||||
instanceIDCol: projection.GoogleInstanceIDCol,
|
||||
}
|
||||
GoogleIDCol = Column{
|
||||
name: projection.GoogleIDCol,
|
||||
table: googleIdpTemplateTable,
|
||||
}
|
||||
GoogleInstanceIDCol = Column{
|
||||
name: projection.GoogleInstanceIDCol,
|
||||
table: googleIdpTemplateTable,
|
||||
}
|
||||
GoogleClientIDCol = Column{
|
||||
name: projection.GoogleClientIDCol,
|
||||
table: googleIdpTemplateTable,
|
||||
}
|
||||
GoogleClientSecretCol = Column{
|
||||
name: projection.GoogleClientSecretCol,
|
||||
table: googleIdpTemplateTable,
|
||||
}
|
||||
GoogleScopesCol = Column{
|
||||
name: projection.GoogleScopesCol,
|
||||
table: googleIdpTemplateTable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ldapIdpTemplateTable = table{
|
||||
name: projection.IDPTemplateLDAPTable,
|
||||
@ -335,6 +370,10 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
IDPTemplateIsLinkingAllowedCol.identifier(),
|
||||
IDPTemplateIsAutoCreationCol.identifier(),
|
||||
IDPTemplateIsAutoUpdateCol.identifier(),
|
||||
GoogleIDCol.identifier(),
|
||||
GoogleClientIDCol.identifier(),
|
||||
GoogleClientSecretCol.identifier(),
|
||||
GoogleScopesCol.identifier(),
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
@ -358,11 +397,19 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
LDAPAvatarURLAttributeCol.identifier(),
|
||||
LDAPProfileAttributeCol.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
LeftJoin(join(GoogleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*IDPTemplate, error) {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
|
||||
name := sql.NullString{}
|
||||
|
||||
googleID := sql.NullString{}
|
||||
googleClientID := sql.NullString{}
|
||||
googleClientSecret := new(crypto.CryptoValue)
|
||||
googleScopes := database.StringArray{}
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
@ -393,13 +440,17 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
&idpTemplate.ChangeDate,
|
||||
&idpTemplate.Sequence,
|
||||
&idpTemplate.State,
|
||||
&idpTemplate.Name,
|
||||
&name,
|
||||
&idpTemplate.Type,
|
||||
&idpTemplate.OwnerType,
|
||||
&idpTemplate.IsCreationAllowed,
|
||||
&idpTemplate.IsLinkingAllowed,
|
||||
&idpTemplate.IsAutoCreation,
|
||||
&idpTemplate.IsAutoUpdate,
|
||||
&googleID,
|
||||
&googleClientID,
|
||||
&googleClientSecret,
|
||||
&googleScopes,
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
@ -430,7 +481,16 @@ func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTempla
|
||||
return nil, errors.ThrowInternal(err, "QUERY-ADG42", "Errors.Internal")
|
||||
}
|
||||
|
||||
if ldapID.Valid {
|
||||
idpTemplate.Name = name.String
|
||||
|
||||
if googleID.Valid {
|
||||
idpTemplate.GoogleIDPTemplate = &GoogleIDPTemplate{
|
||||
IDPID: googleID.String,
|
||||
ClientID: googleClientID.String,
|
||||
ClientSecret: googleClientSecret,
|
||||
Scopes: googleScopes,
|
||||
}
|
||||
} else if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
@ -478,6 +538,10 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
IDPTemplateIsLinkingAllowedCol.identifier(),
|
||||
IDPTemplateIsAutoCreationCol.identifier(),
|
||||
IDPTemplateIsAutoUpdateCol.identifier(),
|
||||
GoogleIDCol.identifier(),
|
||||
GoogleClientIDCol.identifier(),
|
||||
GoogleClientSecretCol.identifier(),
|
||||
GoogleScopesCol.identifier(),
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
@ -502,6 +566,7 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
LDAPProfileAttributeCol.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
LeftJoin(join(GoogleIDCol, IDPTemplateIDCol)).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPTemplates, error) {
|
||||
@ -510,6 +575,13 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
for rows.Next() {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
|
||||
name := sql.NullString{}
|
||||
|
||||
googleID := sql.NullString{}
|
||||
googleClientID := sql.NullString{}
|
||||
googleClientSecret := new(crypto.CryptoValue)
|
||||
googleScopes := database.StringArray{}
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
@ -540,13 +612,17 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
&idpTemplate.ChangeDate,
|
||||
&idpTemplate.Sequence,
|
||||
&idpTemplate.State,
|
||||
&idpTemplate.Name,
|
||||
&name,
|
||||
&idpTemplate.Type,
|
||||
&idpTemplate.OwnerType,
|
||||
&idpTemplate.IsCreationAllowed,
|
||||
&idpTemplate.IsLinkingAllowed,
|
||||
&idpTemplate.IsAutoCreation,
|
||||
&idpTemplate.IsAutoUpdate,
|
||||
&googleID,
|
||||
&googleClientID,
|
||||
&googleClientSecret,
|
||||
&googleScopes,
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
@ -576,7 +652,16 @@ func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplate
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ldapID.Valid {
|
||||
idpTemplate.Name = name.String
|
||||
|
||||
if googleID.Valid {
|
||||
idpTemplate.GoogleIDPTemplate = &GoogleIDPTemplate{
|
||||
IDPID: googleID.String,
|
||||
ClientID: googleClientID.String,
|
||||
ClientSecret: googleClientSecret,
|
||||
Scopes: googleScopes,
|
||||
}
|
||||
} else if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
@ -27,6 +28,10 @@ var (
|
||||
` projections.idp_templates.is_linking_allowed,` +
|
||||
` projections.idp_templates.is_auto_creation,` +
|
||||
` projections.idp_templates.is_auto_update,` +
|
||||
` projections.idp_templates_google.idp_id,` +
|
||||
` projections.idp_templates_google.client_id,` +
|
||||
` projections.idp_templates_google.client_secret,` +
|
||||
` projections.idp_templates_google.scopes,` +
|
||||
` projections.idp_templates_ldap.idp_id,` +
|
||||
` projections.idp_templates_ldap.host,` +
|
||||
` projections.idp_templates_ldap.port,` +
|
||||
@ -50,6 +55,7 @@ var (
|
||||
` projections.idp_templates_ldap.avatar_url_attribute,` +
|
||||
` projections.idp_templates_ldap.profile_attribute` +
|
||||
` FROM projections.idp_templates` +
|
||||
` LEFT JOIN projections.idp_templates_google ON projections.idp_templates.id = projections.idp_templates_google.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates_ldap ON projections.idp_templates.id = projections.idp_templates_ldap.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_ldap.instance_id`
|
||||
idpTemplateCols = []string{
|
||||
"id",
|
||||
@ -65,6 +71,11 @@ var (
|
||||
"is_linking_allowed",
|
||||
"is_auto_creation",
|
||||
"is_auto_update",
|
||||
// google config
|
||||
"idp_id",
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"scopes",
|
||||
// ldap config
|
||||
"idp_id",
|
||||
"host",
|
||||
@ -102,6 +113,10 @@ var (
|
||||
` projections.idp_templates.is_linking_allowed,` +
|
||||
` projections.idp_templates.is_auto_creation,` +
|
||||
` projections.idp_templates.is_auto_update,` +
|
||||
` projections.idp_templates_google.idp_id,` +
|
||||
` projections.idp_templates_google.client_id,` +
|
||||
` projections.idp_templates_google.client_secret,` +
|
||||
` projections.idp_templates_google.scopes,` +
|
||||
` projections.idp_templates_ldap.idp_id,` +
|
||||
` projections.idp_templates_ldap.host,` +
|
||||
` projections.idp_templates_ldap.port,` +
|
||||
@ -126,6 +141,7 @@ var (
|
||||
` projections.idp_templates_ldap.profile_attribute,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_templates` +
|
||||
` LEFT JOIN projections.idp_templates_google ON projections.idp_templates.id = projections.idp_templates_google.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates_ldap ON projections.idp_templates.id = projections.idp_templates_ldap.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_ldap.instance_id`
|
||||
idpTemplatesCols = []string{
|
||||
"id",
|
||||
@ -141,6 +157,12 @@ var (
|
||||
"is_linking_allowed",
|
||||
"is_auto_creation",
|
||||
"is_auto_update",
|
||||
// google config
|
||||
"idp_id",
|
||||
"client_id",
|
||||
"client_secret",
|
||||
"scopes",
|
||||
// ldap config
|
||||
"idp_id",
|
||||
"host",
|
||||
"port",
|
||||
@ -196,6 +218,81 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
},
|
||||
object: (*IDPTemplate)(nil),
|
||||
},
|
||||
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery google idp",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
idpTemplateCols,
|
||||
[]driver.Value{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeGoogle,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google
|
||||
"idp-id",
|
||||
"client_id",
|
||||
nil,
|
||||
database.StringArray{"profile"},
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplate{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeGoogle,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
GoogleIDPTemplate: &GoogleIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: nil,
|
||||
Scopes: []string{"profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery ldap idp",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
@ -217,6 +314,11 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
@ -305,6 +407,11 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@ -404,6 +511,11 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
@ -501,6 +613,11 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@ -560,7 +677,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
idpTemplatesCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"idp-id-1",
|
||||
"idp-id-ldap",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
@ -573,8 +690,13 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"idp-id-ldap",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
@ -598,19 +720,24 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
"profile",
|
||||
},
|
||||
{
|
||||
"idp-id-2",
|
||||
"idp-id-google",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IDPTypeGoogle,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// google
|
||||
"idp-id-google",
|
||||
"client_id",
|
||||
nil,
|
||||
database.StringArray{"profile"},
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
@ -648,7 +775,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id-1",
|
||||
ID: "idp-id-ldap",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
@ -658,7 +785,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
IDPID: "idp-id-ldap",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
@ -688,15 +815,21 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id-2",
|
||||
ID: "idp-id-google",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
Type: domain.IDPTypeGoogle,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
GoogleIDPTemplate: &GoogleIDPTemplate{
|
||||
IDPID: "idp-id-google",
|
||||
ClientID: "client_id",
|
||||
ClientSecret: nil,
|
||||
Scopes: []string{"profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2,7 +2,9 @@ package projection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -14,10 +16,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
IDPTemplateTable = "projections.idp_templates"
|
||||
IDPTemplateLDAPTable = IDPTemplateTable + "_" + IDPTemplateLDAPSuffix
|
||||
IDPTemplateTable = "projections.idp_templates"
|
||||
IDPTemplateGoogleTable = IDPTemplateTable + "_" + IDPTemplateGoogleSuffix
|
||||
IDPTemplateLDAPTable = IDPTemplateTable + "_" + IDPTemplateLDAPSuffix
|
||||
|
||||
IDPTemplateLDAPSuffix = "ldap"
|
||||
IDPTemplateGoogleSuffix = "google"
|
||||
IDPTemplateLDAPSuffix = "ldap"
|
||||
|
||||
IDPTemplateIDCol = "id"
|
||||
IDPTemplateCreationDateCol = "creation_date"
|
||||
@ -35,6 +39,12 @@ const (
|
||||
IDPTemplateIsAutoCreationCol = "is_auto_creation"
|
||||
IDPTemplateIsAutoUpdateCol = "is_auto_update"
|
||||
|
||||
GoogleIDCol = "idp_id"
|
||||
GoogleInstanceIDCol = "instance_id"
|
||||
GoogleClientIDCol = "client_id"
|
||||
GoogleClientSecretCol = "client_secret"
|
||||
GoogleScopesCol = "scopes"
|
||||
|
||||
LDAPIDCol = "idp_id"
|
||||
LDAPInstanceIDCol = "instance_id"
|
||||
LDAPHostCol = "host"
|
||||
@ -90,6 +100,17 @@ func newIDPTemplateProjection(ctx context.Context, config crdb.StatementHandlerC
|
||||
crdb.WithIndex(crdb.NewIndex("resource_owner", []string{IDPTemplateResourceOwnerCol})),
|
||||
crdb.WithIndex(crdb.NewIndex("owner_removed", []string{IDPTemplateOwnerRemovedCol})),
|
||||
),
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(GoogleIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(GoogleInstanceIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(GoogleClientIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(GoogleClientSecretCol, crdb.ColumnTypeJSONB),
|
||||
crdb.NewColumn(GoogleScopesCol, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
||||
},
|
||||
crdb.NewPrimaryKey(GoogleInstanceIDCol, GoogleIDCol),
|
||||
IDPTemplateGoogleSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()),
|
||||
),
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(LDAPIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPInstanceIDCol, crdb.ColumnTypeText),
|
||||
@ -129,6 +150,14 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer {
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventRedusers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.GoogleIDPAddedEventType,
|
||||
Reduce: p.reduceGoogleIDPAdded,
|
||||
},
|
||||
{
|
||||
Event: instance.GoogleIDPChangedEventType,
|
||||
Reduce: p.reduceGoogleIDPChanged,
|
||||
},
|
||||
{
|
||||
Event: instance.LDAPIDPAddedEventType,
|
||||
Reduce: p.reduceLDAPIDPAdded,
|
||||
@ -150,6 +179,14 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer {
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventRedusers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.GoogleIDPAddedEventType,
|
||||
Reduce: p.reduceGoogleIDPAdded,
|
||||
},
|
||||
{
|
||||
Event: org.GoogleIDPChangedEventType,
|
||||
Reduce: p.reduceGoogleIDPChanged,
|
||||
},
|
||||
{
|
||||
Event: org.LDAPIDPAddedEventType,
|
||||
Reduce: p.reduceLDAPIDPAdded,
|
||||
@ -171,6 +208,94 @@ func (p *idpTemplateProjection) reducers() []handler.AggregateReducer {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceGoogleIDPAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.GoogleIDPAddedEvent
|
||||
var idpOwnerType domain.IdentityProviderType
|
||||
switch e := event.(type) {
|
||||
case *org.GoogleIDPAddedEvent:
|
||||
idpEvent = e.GoogleIDPAddedEvent
|
||||
idpOwnerType = domain.IdentityProviderTypeOrg
|
||||
case *instance.GoogleIDPAddedEvent:
|
||||
idpEvent = e.GoogleIDPAddedEvent
|
||||
idpOwnerType = domain.IdentityProviderTypeSystem
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-ap9ihb", "reduce.wrong.event.type %v", []eventstore.EventType{org.GoogleIDPAddedEventType, instance.GoogleIDPAddedEventType})
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(
|
||||
&idpEvent,
|
||||
crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
|
||||
handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner),
|
||||
handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive),
|
||||
handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
|
||||
handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType),
|
||||
handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeGoogle),
|
||||
handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
|
||||
handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
|
||||
handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
|
||||
handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
|
||||
},
|
||||
),
|
||||
crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(GoogleIDCol, idpEvent.ID),
|
||||
handler.NewCol(GoogleInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
handler.NewCol(GoogleClientIDCol, idpEvent.ClientID),
|
||||
handler.NewCol(GoogleClientSecretCol, idpEvent.ClientSecret),
|
||||
handler.NewCol(GoogleScopesCol, database.StringArray(idpEvent.Scopes)),
|
||||
},
|
||||
crdb.WithTableSuffix(IDPTemplateGoogleSuffix),
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceGoogleIDPChanged(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.GoogleIDPChangedEvent
|
||||
switch e := event.(type) {
|
||||
case *org.GoogleIDPChangedEvent:
|
||||
idpEvent = e.GoogleIDPChangedEvent
|
||||
case *instance.GoogleIDPChangedEvent:
|
||||
idpEvent = e.GoogleIDPChangedEvent
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.GoogleIDPChangedEventType, instance.GoogleIDPChangedEventType})
|
||||
}
|
||||
|
||||
ops := make([]func(eventstore.Event) crdb.Exec, 0, 2)
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges),
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
},
|
||||
),
|
||||
)
|
||||
googleCols := reduceGoogleIDPChangedColumns(idpEvent)
|
||||
if len(googleCols) > 0 {
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
googleCols,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(GoogleIDCol, idpEvent.ID),
|
||||
handler.NewCond(GoogleInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
},
|
||||
crdb.WithTableSuffix(IDPTemplateGoogleSuffix),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(
|
||||
&idpEvent,
|
||||
ops...,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceLDAPIDPAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.LDAPIDPAddedEvent
|
||||
var idpOwnerType domain.IdentityProviderType
|
||||
@ -247,13 +372,10 @@ func (p *idpTemplateProjection) reduceLDAPIDPChanged(event eventstore.Event) (*h
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.LDAPIDPChangedEventType, instance.LDAPIDPChangedEventType})
|
||||
}
|
||||
|
||||
cols := reduceLDAPIDPChangedTemplateColumns(idpEvent)
|
||||
ldapCols := reduceLDAPIDPChangedLDAPColumns(idpEvent)
|
||||
|
||||
ops := make([]func(eventstore.Event) crdb.Exec, 0, 2)
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
cols,
|
||||
reduceIDPChangedTemplateColumns(idpEvent.Name, idpEvent.CreationDate(), idpEvent.Sequence(), idpEvent.OptionChanges),
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
@ -261,6 +383,7 @@ func (p *idpTemplateProjection) reduceLDAPIDPChanged(event eventstore.Event) (*h
|
||||
),
|
||||
)
|
||||
|
||||
ldapCols := reduceLDAPIDPChangedColumns(idpEvent)
|
||||
if len(ldapCols) > 0 {
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
@ -320,30 +443,44 @@ func (p *idpTemplateProjection) reduceOwnerRemoved(event eventstore.Event) (*han
|
||||
), nil
|
||||
}
|
||||
|
||||
func reduceLDAPIDPChangedTemplateColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
func reduceIDPChangedTemplateColumns(name *string, creationDate time.Time, sequence uint64, optionChanges idp.OptionChanges) []handler.Column {
|
||||
cols := make([]handler.Column, 0, 7)
|
||||
if idpEvent.Name != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateNameCol, *idpEvent.Name))
|
||||
if name != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateNameCol, *name))
|
||||
}
|
||||
if idpEvent.IsCreationAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsCreationAllowedCol, *idpEvent.IsCreationAllowed))
|
||||
if optionChanges.IsCreationAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsCreationAllowedCol, *optionChanges.IsCreationAllowed))
|
||||
}
|
||||
if idpEvent.IsLinkingAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsLinkingAllowedCol, *idpEvent.IsLinkingAllowed))
|
||||
if optionChanges.IsLinkingAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsLinkingAllowedCol, *optionChanges.IsLinkingAllowed))
|
||||
}
|
||||
if idpEvent.IsAutoCreation != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoCreationCol, *idpEvent.IsAutoCreation))
|
||||
if optionChanges.IsAutoCreation != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoCreationCol, *optionChanges.IsAutoCreation))
|
||||
}
|
||||
if idpEvent.IsAutoUpdate != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoUpdateCol, *idpEvent.IsAutoUpdate))
|
||||
if optionChanges.IsAutoUpdate != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoUpdateCol, *optionChanges.IsAutoUpdate))
|
||||
}
|
||||
return append(cols,
|
||||
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
|
||||
handler.NewCol(IDPTemplateChangeDateCol, creationDate),
|
||||
handler.NewCol(IDPTemplateSequenceCol, sequence),
|
||||
)
|
||||
}
|
||||
|
||||
func reduceLDAPIDPChangedLDAPColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
func reduceGoogleIDPChangedColumns(idpEvent idp.GoogleIDPChangedEvent) []handler.Column {
|
||||
googleCols := make([]handler.Column, 0, 3)
|
||||
if idpEvent.ClientID != nil {
|
||||
googleCols = append(googleCols, handler.NewCol(GoogleClientIDCol, *idpEvent.ClientID))
|
||||
}
|
||||
if idpEvent.ClientSecret != nil {
|
||||
googleCols = append(googleCols, handler.NewCol(GoogleClientSecretCol, *idpEvent.ClientSecret))
|
||||
}
|
||||
if idpEvent.Scopes != nil {
|
||||
googleCols = append(googleCols, handler.NewCol(GoogleScopesCol, database.StringArray(idpEvent.Scopes)))
|
||||
}
|
||||
return googleCols
|
||||
}
|
||||
|
||||
func reduceLDAPIDPChangedColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
ldapCols := make([]handler.Column, 0, 4)
|
||||
if idpEvent.Host != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPHostCol, *idpEvent.Host))
|
||||
|
@ -3,6 +3,7 @@ package projection
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -124,6 +125,254 @@ func TestIDPTemplateProjection_reducesRemove(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDPTemplateProjection_reducesGoogle(t *testing.T) {
|
||||
type args struct {
|
||||
event func(t *testing.T) eventstore.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||
want wantReduce
|
||||
}{
|
||||
{
|
||||
name: "instance reduceGoogleIDPAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.GoogleIDPAddedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"clientID": "client_id",
|
||||
"clientSecret": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"scopes": ["profile"],
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), instance.GoogleIDPAddedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceGoogleIDPAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, owner_type, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"ro-id",
|
||||
"instance-id",
|
||||
domain.IDPStateActive,
|
||||
"",
|
||||
domain.IdentityProviderTypeSystem,
|
||||
domain.IDPTypeGoogle,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"client_id",
|
||||
anyArg{},
|
||||
database.StringArray{"profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org reduceGoogleIDPAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(org.GoogleIDPAddedEventType),
|
||||
org.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"clientID": "client_id",
|
||||
"clientSecret": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"scopes": ["profile"],
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), org.GoogleIDPAddedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceGoogleIDPAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("org"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, owner_type, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"ro-id",
|
||||
"instance-id",
|
||||
domain.IDPStateActive,
|
||||
"",
|
||||
domain.IdentityProviderTypeOrg,
|
||||
domain.IDPTypeGoogle,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates_google (idp_id, instance_id, client_id, client_secret, scopes) VALUES ($1, $2, $3, $4, $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"client_id",
|
||||
anyArg{},
|
||||
database.StringArray{"profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceGoogleIDPChanged minimal",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.GoogleIDPChangedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"isCreationAllowed": true,
|
||||
"clientID": "id"
|
||||
}`),
|
||||
), instance.GoogleIDPChangedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceGoogleIDPChanged,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (is_creation_allowed, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
true,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates_google SET client_id = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"id",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceGoogleIDPChanged",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.GoogleIDPChangedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"clientID": "client_id",
|
||||
"clientSecret": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"scopes": ["profile"],
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), instance.GoogleIDPChangedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceGoogleIDPChanged,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence) = ($1, $2, $3, $4, $5, $6) WHERE (id = $7) AND (instance_id = $8)",
|
||||
expectedArgs: []interface{}{
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates_google SET (client_id, client_secret, scopes) = ($1, $2, $3) WHERE (idp_id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"client_id",
|
||||
anyArg{},
|
||||
database.StringArray{"profile"},
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := baseEvent(t)
|
||||
got, err := tt.reduce(event)
|
||||
if !errors.IsErrorInvalidArgument(err) {
|
||||
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||
}
|
||||
|
||||
event = tt.args.event(t)
|
||||
got, err = tt.reduce(event)
|
||||
assertReduce(t, got, err, IDPTemplateTable, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
type args struct {
|
||||
event func(t *testing.T) eventstore.Event
|
||||
|
143
internal/repository/idp/google.go
Normal file
143
internal/repository/idp/google.go
Normal file
@ -0,0 +1,143 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
|
||||
type GoogleIDPAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ClientID string `json:"clientID"`
|
||||
ClientSecret *crypto.CryptoValue `json:"clientSecret"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
Options
|
||||
}
|
||||
|
||||
func NewGoogleIDPAddedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id,
|
||||
name,
|
||||
clientID string,
|
||||
clientSecret *crypto.CryptoValue,
|
||||
scopes []string,
|
||||
options Options,
|
||||
) *GoogleIDPAddedEvent {
|
||||
return &GoogleIDPAddedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
Name: name,
|
||||
ClientID: clientID,
|
||||
ClientSecret: clientSecret,
|
||||
Scopes: scopes,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GoogleIDPAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GoogleIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GoogleIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &GoogleIDPAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "IDP-SAff1", "unable to unmarshal event")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GoogleIDPChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ClientID *string `json:"clientID,omitempty"`
|
||||
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
OptionChanges
|
||||
}
|
||||
|
||||
func NewGoogleIDPChangedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id string,
|
||||
changes []GoogleIDPChanges,
|
||||
) (*GoogleIDPChangedEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "IDP-Dg3qs", "Errors.NoChangesFound")
|
||||
}
|
||||
changedEvent := &GoogleIDPChangedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changedEvent)
|
||||
}
|
||||
return changedEvent, nil
|
||||
}
|
||||
|
||||
type GoogleIDPChanges func(*GoogleIDPChangedEvent)
|
||||
|
||||
func ChangeGoogleName(name string) func(*GoogleIDPChangedEvent) {
|
||||
return func(e *GoogleIDPChangedEvent) {
|
||||
e.Name = &name
|
||||
}
|
||||
}
|
||||
func ChangeGoogleClientID(clientID string) func(*GoogleIDPChangedEvent) {
|
||||
return func(e *GoogleIDPChangedEvent) {
|
||||
e.ClientID = &clientID
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeGoogleClientSecret(clientSecret *crypto.CryptoValue) func(*GoogleIDPChangedEvent) {
|
||||
return func(e *GoogleIDPChangedEvent) {
|
||||
e.ClientSecret = clientSecret
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeGoogleScopes(scopes []string) func(*GoogleIDPChangedEvent) {
|
||||
return func(e *GoogleIDPChangedEvent) {
|
||||
e.Scopes = scopes
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeGoogleOptions(options OptionChanges) func(*GoogleIDPChangedEvent) {
|
||||
return func(e *GoogleIDPChangedEvent) {
|
||||
e.OptionChanges = options
|
||||
}
|
||||
}
|
||||
|
||||
func (e *GoogleIDPChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GoogleIDPChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GoogleIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &GoogleIDPChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "IDP-SF3t2", "unable to unmarshal event")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
@ -70,6 +70,8 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(AggregateType, IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigAddedEventType, IDPJWTConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigChangedEventType, IDPJWTConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, GoogleIDPAddedEventType, GoogleIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, GoogleIDPChangedEventType, GoogleIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPAddedEventType, LDAPIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPChangedEventType, LDAPIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPRemovedEventType, IDPRemovedEventMapper).
|
||||
|
@ -10,11 +10,89 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LDAPIDPAddedEventType eventstore.EventType = "instance.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "instance.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "instance.idp.removed"
|
||||
GoogleIDPAddedEventType eventstore.EventType = "instance.idp.google.added"
|
||||
GoogleIDPChangedEventType eventstore.EventType = "instance.idp.google.changed"
|
||||
LDAPIDPAddedEventType eventstore.EventType = "instance.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "instance.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "instance.idp.removed"
|
||||
)
|
||||
|
||||
type GoogleIDPAddedEvent struct {
|
||||
idp.GoogleIDPAddedEvent
|
||||
}
|
||||
|
||||
func NewGoogleIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
clientID string,
|
||||
clientSecret *crypto.CryptoValue,
|
||||
scopes []string,
|
||||
options idp.Options,
|
||||
) *GoogleIDPAddedEvent {
|
||||
|
||||
return &GoogleIDPAddedEvent{
|
||||
GoogleIDPAddedEvent: *idp.NewGoogleIDPAddedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
GoogleIDPAddedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
clientID,
|
||||
clientSecret,
|
||||
scopes,
|
||||
options,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func GoogleIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.GoogleIDPAddedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GoogleIDPAddedEvent{GoogleIDPAddedEvent: *e.(*idp.GoogleIDPAddedEvent)}, nil
|
||||
}
|
||||
|
||||
type GoogleIDPChangedEvent struct {
|
||||
idp.GoogleIDPChangedEvent
|
||||
}
|
||||
|
||||
func NewGoogleIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
changes []idp.GoogleIDPChanges,
|
||||
) (*GoogleIDPChangedEvent, error) {
|
||||
|
||||
changedEvent, err := idp.NewGoogleIDPChangedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
GoogleIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GoogleIDPChangedEvent{GoogleIDPChangedEvent: *changedEvent}, nil
|
||||
}
|
||||
|
||||
func GoogleIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.GoogleIDPChangedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GoogleIDPChangedEvent{GoogleIDPChangedEvent: *e.(*idp.GoogleIDPChangedEvent)}, nil
|
||||
}
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
idp.LDAPIDPAddedEvent
|
||||
}
|
||||
|
@ -78,6 +78,8 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(AggregateType, IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigAddedEventType, IDPJWTConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigChangedEventType, IDPJWTConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, GoogleIDPAddedEventType, GoogleIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, GoogleIDPChangedEventType, GoogleIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPAddedEventType, LDAPIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPChangedEventType, LDAPIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPRemovedEventType, IDPRemovedEventMapper).
|
||||
|
@ -10,11 +10,89 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
LDAPIDPAddedEventType eventstore.EventType = "org.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "org.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "org.idp.removed"
|
||||
GoogleIDPAddedEventType eventstore.EventType = "org.idp.google.added"
|
||||
GoogleIDPChangedEventType eventstore.EventType = "org.idp.google.changed"
|
||||
LDAPIDPAddedEventType eventstore.EventType = "org.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "org.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "org.idp.removed"
|
||||
)
|
||||
|
||||
type GoogleIDPAddedEvent struct {
|
||||
idp.GoogleIDPAddedEvent
|
||||
}
|
||||
|
||||
func NewGoogleIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
clientID string,
|
||||
clientSecret *crypto.CryptoValue,
|
||||
scopes []string,
|
||||
options idp.Options,
|
||||
) *GoogleIDPAddedEvent {
|
||||
|
||||
return &GoogleIDPAddedEvent{
|
||||
GoogleIDPAddedEvent: *idp.NewGoogleIDPAddedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
GoogleIDPAddedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
clientID,
|
||||
clientSecret,
|
||||
scopes,
|
||||
options,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func GoogleIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.GoogleIDPAddedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GoogleIDPAddedEvent{GoogleIDPAddedEvent: *e.(*idp.GoogleIDPAddedEvent)}, nil
|
||||
}
|
||||
|
||||
type GoogleIDPChangedEvent struct {
|
||||
idp.GoogleIDPChangedEvent
|
||||
}
|
||||
|
||||
func NewGoogleIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
changes []idp.GoogleIDPChanges,
|
||||
) (*GoogleIDPChangedEvent, error) {
|
||||
|
||||
changedEvent, err := idp.NewGoogleIDPChangedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
GoogleIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GoogleIDPChangedEvent{GoogleIDPChangedEvent: *changedEvent}, nil
|
||||
}
|
||||
|
||||
func GoogleIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.GoogleIDPChangedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GoogleIDPChangedEvent{GoogleIDPChangedEvent: *e.(*idp.GoogleIDPChangedEvent)}, nil
|
||||
}
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
idp.LDAPIDPAddedEvent
|
||||
}
|
||||
|
@ -1033,7 +1033,31 @@ service AdminService {
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new ldap identity provider on the instance
|
||||
// Add a new Google identity provider on the instance
|
||||
rpc AddGoogleProvider(AddGoogleProviderRequest) returns (AddGoogleProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/google"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "iam.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing Google identity provider on the instance
|
||||
rpc UpdateGoogleProvider(UpdateGoogleProviderRequest) returns (UpdateGoogleProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/idps/google/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "iam.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new LDAP identity provider on the instance
|
||||
rpc AddLDAPProvider(AddLDAPProviderRequest) returns (AddLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap"
|
||||
@ -1045,7 +1069,7 @@ service AdminService {
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing ldap identity provider on the instance
|
||||
// Change an existing LDAP identity provider on the instance
|
||||
rpc UpdateLDAPProvider(UpdateLDAPProviderRequest) returns (UpdateLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/idps/ldap/{id}"
|
||||
@ -3710,6 +3734,34 @@ message GetProviderByIDResponse {
|
||||
zitadel.idp.v1.Provider idp = 1;
|
||||
}
|
||||
|
||||
message AddGoogleProviderRequest {
|
||||
// Google will be used as default, if no name is provided
|
||||
string name = 1 [(validate.rules).string = {max_len: 200}];
|
||||
string client_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string client_secret = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string scopes = 4 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||
zitadel.idp.v1.Options provider_options = 5;
|
||||
}
|
||||
|
||||
message AddGoogleProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message UpdateGoogleProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {max_len: 200}];
|
||||
string client_id = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
// client_secret will only be updated if provided
|
||||
string client_secret = 4 [(validate.rules).string = {max_len: 200}];
|
||||
repeated string scopes = 5 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||
zitadel.idp.v1.Options provider_options = 6;
|
||||
}
|
||||
|
||||
message UpdateGoogleProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
|
@ -262,9 +262,15 @@ message ProviderConfig {
|
||||
Options options = 1;
|
||||
oneof config {
|
||||
LDAPConfig ldap = 2;
|
||||
GoogleConfig google = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message GoogleConfig {
|
||||
string client_id = 1;
|
||||
repeated string scopes = 2;
|
||||
}
|
||||
|
||||
message LDAPConfig {
|
||||
string host = 1;
|
||||
string port = 2;
|
||||
|
@ -3031,7 +3031,32 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new ldap identity provider in the organisation
|
||||
|
||||
// Add a new Google identity provider in the organisation
|
||||
rpc AddGoogleProvider(AddGoogleProviderRequest) returns (AddGoogleProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/google"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing Google identity provider in the organisation
|
||||
rpc UpdateGoogleProvider(UpdateGoogleProviderRequest) returns (UpdateGoogleProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/idps/google/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new LDAP identity provider in the organisation
|
||||
rpc AddLDAPProvider(AddLDAPProviderRequest) returns (AddLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap"
|
||||
@ -3043,7 +3068,7 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing ldap identity provider in the organisation
|
||||
// Change an existing LDAP identity provider in the organisation
|
||||
rpc UpdateLDAPProvider(UpdateLDAPProviderRequest) returns (UpdateLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
put: "/idps/ldap/{id}"
|
||||
@ -6008,6 +6033,34 @@ message GetProviderByIDResponse {
|
||||
zitadel.idp.v1.Provider idp = 1;
|
||||
}
|
||||
|
||||
message AddGoogleProviderRequest {
|
||||
// Google will be used as default, if no name is provided
|
||||
string name = 1 [(validate.rules).string = {max_len: 200}];
|
||||
string client_id = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string client_secret = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string scopes = 4 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||
zitadel.idp.v1.Options provider_options = 5;
|
||||
}
|
||||
|
||||
message AddGoogleProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message UpdateGoogleProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {max_len: 200}];
|
||||
string client_id = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
// client_secret will only be updated if provided
|
||||
string client_secret = 4 [(validate.rules).string = {max_len: 200}];
|
||||
repeated string scopes = 5 [(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}}];
|
||||
zitadel.idp.v1.Options provider_options = 6;
|
||||
}
|
||||
|
||||
message UpdateGoogleProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
|
Loading…
x
Reference in New Issue
Block a user