feat: project roles (#843)

* fix logging

* token verification

* feat: assert roles

* feat: add project role assertion on project and token type on app

* id and access token role assertion

* add project role check

* user grant required step in login

* update library

* fix merge

* fix merge

* fix merge

* update oidc library

* fix tests

* add tests for GrantRequiredStep

* add missing field ProjectRoleCheck on project view model

* fix project create

* fix project create
This commit is contained in:
Livio Amstutz
2020-10-16 07:49:38 +02:00
committed by GitHub
parent f5a7a0a09f
commit a321d850ae
57 changed files with 10894 additions and 18297 deletions

View File

@@ -2,28 +2,30 @@ package eventstore
import (
"context"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/eventstore/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
"time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/auth_request/model"
cache "github.com/caos/zitadel/internal/auth_request/repository"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/sdk"
iam_model "github.com/caos/zitadel/internal/iam/model"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/id"
org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
project_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
user_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
)
type AuthRequestRepo struct {
@@ -38,6 +40,7 @@ type AuthRequestRepo struct {
OrgViewProvider orgViewProvider
LoginPolicyViewProvider loginPolicyViewProvider
IDPProviderViewProvider idpProviderViewProvider
UserGrantProvider userGrantProvider
IdGenerator id.Generator
@@ -76,6 +79,11 @@ type orgViewProvider interface {
OrgByPrimaryDomain(string) (*org_view_model.OrgView, error)
}
type userGrantProvider interface {
ApplicationByClientID(context.Context, string) (*project_view_model.ApplicationView, error)
UserGrantsByProjectAndUserID(string, string) ([]*grant_view_model.UserGrantView, error)
}
func (repo *AuthRequestRepo) Health(ctx context.Context) error {
if err := repo.UserEvents.Health(ctx); err != nil {
return err
@@ -89,14 +97,18 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod
return nil, err
}
request.ID = reqID
ids, err := repo.View.AppIDsFromProjectByClientID(ctx, request.ApplicationID)
app, err := repo.View.ApplicationByClientID(ctx, request.ApplicationID)
if err != nil {
return nil, err
}
request.Audience = ids
appIDs, err := repo.View.AppIDsFromProjectID(ctx, app.ProjectID)
if err != nil {
return nil, err
}
request.Audience = appIDs
if request.LoginHint != "" {
err = repo.checkLoginName(ctx, request, request.LoginHint)
logging.LogWithFields("EVENT-aG311", "login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID).Debug("login hint invalid")
logging.LogWithFields("EVENT-aG311", "login name", request.LoginHint, "id", request.ID, "applicationID", request.ApplicationID).OnError(err).Debug("login hint invalid")
}
err = repo.AuthRequests.SaveAuthRequest(ctx, request)
if err != nil {
@@ -541,6 +553,15 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
}
//PLANNED: consent step
missing, err := userGrantRequired(ctx, request, user, repo.UserGrantProvider)
if err != nil {
return nil, err
}
if missing {
return append(steps, &model.GrantRequiredStep{}), nil
}
return append(steps, &model.RedirectToCallbackStep{}), nil
}
@@ -780,3 +801,23 @@ func linkingIDPConfigExistingInAllowedIDPs(linkingUsers []*model.ExternalUser, i
}
return true
}
func userGrantRequired(ctx context.Context, request *model.AuthRequest, user *user_model.UserView, userGrantProvider userGrantProvider) (_ bool, err error) {
var app *project_view_model.ApplicationView
switch request.Request.Type() {
case model.AuthRequestTypeOIDC:
app, err = userGrantProvider.ApplicationByClientID(ctx, request.ApplicationID)
if err != nil {
return false, err
}
default:
return false, errors.ThrowPreconditionFailed(nil, "EVENT-dfrw2", "Errors.AuthRequest.RequestTypeNotSupported")
}
if !app.ProjectRoleCheck {
return false, nil
}
grants, err := userGrantProvider.UserGrantsByProjectAndUserID(app.ProjectID, user.ID)
if err != nil {
return false, err
}
return len(grants) == 0, nil
}

View File

@@ -15,10 +15,12 @@ import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
user_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model"
)
type mockViewNoUserSession struct{}
@@ -157,6 +159,23 @@ func (m *mockViewErrOrg) OrgByPrimaryDomain(string) (*org_view_model.OrgView, er
return nil, errors.ThrowInternal(nil, "id", "internal error")
}
type mockUserGrants struct {
roleCheck bool
userGrants int
}
func (m *mockUserGrants) ApplicationByClientID(ctx context.Context, s string) (*proj_view_model.ApplicationView, error) {
return &proj_view_model.ApplicationView{ProjectRoleCheck: m.roleCheck}, nil
}
func (m *mockUserGrants) UserGrantsByProjectAndUserID(s string, s2 string) ([]*grant_view_model.UserGrantView, error) {
var grants []*grant_view_model.UserGrantView
if m.userGrants > 0 {
grants = make([]*grant_view_model.UserGrantView, m.userGrants)
}
return grants, nil
}
func TestAuthRequestRepo_nextSteps(t *testing.T) {
type fields struct {
UserEvents *user_event.UserEventstore
@@ -166,6 +185,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider userViewProvider
userEventProvider userEventProvider
orgViewProvider orgViewProvider
userGrantProvider userGrantProvider
PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration
@@ -424,10 +444,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -460,10 +481,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
MfaSoftwareCheckLifeTime: 18 * time.Hour,
ExternalLoginCheckLifeTime: 10 * 24 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID"}, false},
args{&model.AuthRequest{UserID: "UserID", SelectedIDPConfigID: "IDPConfigID", Request: &model.AuthRequestOIDC{}}, false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -590,10 +612,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
args{&model.AuthRequest{UserID: "UserID", Request: &model.AuthRequestOIDC{}}, false},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -611,10 +634,61 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone}, true},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
{
"prompt none, checkLoggedIn true, authenticated and required user grants missing, grant required step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{
roleCheck: true,
userGrants: 0,
},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
[]model.NextStep{&model.GrantRequiredStep{}},
nil,
},
{
"prompt none, checkLoggedIn true, authenticated and required user grants exist, redirect to callback step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordVerification: time.Now().UTC().Add(-5 * time.Minute),
MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
IsEmailVerified: true,
MfaMaxSetUp: int32(model.MfaLevelSoftware),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
userGrantProvider: &mockUserGrants{
roleCheck: true,
userGrants: 2,
},
PasswordCheckLifeTime: 10 * 24 * time.Hour,
MfaSoftwareCheckLifeTime: 18 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone, Request: &model.AuthRequestOIDC{}}, true},
[]model.NextStep{&model.RedirectToCallbackStep{}},
nil,
},
@@ -679,6 +753,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
UserViewProvider: tt.fields.userViewProvider,
UserEventProvider: tt.fields.userEventProvider,
OrgViewProvider: tt.fields.orgViewProvider,
UserGrantProvider: tt.fields.userGrantProvider,
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime,

View File

@@ -0,0 +1,21 @@
package eventstore
import (
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
"github.com/caos/zitadel/internal/project/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
type ProjectRepo struct {
View *view.View
ProjectEvents *proj_event.ProjectEventstore
}
func (a *ApplicationRepo) ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error) {
roles, err := a.View.ProjectRolesByProjectID(projectID)
if err != nil {
return nil, err
}
return proj_view_model.ProjectRolesToModel(roles), nil
}

View File

@@ -52,11 +52,27 @@ func (p *Application) Reduce(event *models.Event) (err error) {
}
err = app.AppendEvent(event)
case es_model.ApplicationRemoved:
err := app.SetData(event)
err = app.SetData(event)
if err != nil {
return err
}
return p.view.DeleteApplication(app.ID, event.Sequence)
case es_model.ProjectChanged:
apps, err := p.view.ApplicationsByProjectID(event.AggregateID)
if err != nil {
return err
}
if len(apps) == 0 {
return p.view.ProcessedApplicationSequence(event.Sequence)
}
for _, app := range apps {
if err := app.AppendEvent(event); err != nil {
return err
}
}
return p.view.PutApplications(apps, event.Sequence)
case es_model.ProjectRemoved:
return p.view.DeleteApplicationsByProjectID(event.AggregateID)
default:
return p.view.ProcessedApplicationSequence(event.Sequence)
}

View File

@@ -60,6 +60,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount}, systemDefaults: systemDefaults, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents},
&PasswordComplexityPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordComplexityPolicy"), errorCount}},
&OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
&ProjectRole{handler: handler{view, bulkLimit, configs.cycleDuration("ProjectRole"), errorCount}, projectEvents: repos.ProjectEvents},
}
}

View File

@@ -0,0 +1,70 @@
package handler
import (
"github.com/caos/logging"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/eventstore/spooler"
"github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
view_model "github.com/caos/zitadel/internal/project/repository/view/model"
)
type ProjectRole struct {
handler
projectEvents *proj_event.ProjectEventstore
}
const (
projectRoleTable = "auth.project_roles"
)
func (p *ProjectRole) ViewModel() string {
return projectRoleTable
}
func (p *ProjectRole) EventQuery() (*models.SearchQuery, error) {
sequence, err := p.view.GetLatestProjectRoleSequence()
if err != nil {
return nil, err
}
return eventsourcing.ProjectQuery(sequence.CurrentSequence), nil
}
func (p *ProjectRole) Reduce(event *models.Event) (err error) {
role := new(view_model.ProjectRoleView)
switch event.Type {
case es_model.ProjectRoleAdded:
err = role.AppendEvent(event)
case es_model.ProjectRoleChanged:
err = role.SetData(event)
if err != nil {
return err
}
role, err = p.view.ProjectRoleByIDs(event.AggregateID, event.ResourceOwner, role.Key)
if err != nil {
return err
}
err = role.AppendEvent(event)
case es_model.ProjectRoleRemoved:
err = role.SetData(event)
if err != nil {
return err
}
return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence)
case es_model.ProjectRemoved:
return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
default:
return p.view.ProcessedProjectRoleSequence(event.Sequence)
}
if err != nil {
return err
}
return p.view.PutProjectRole(role)
}
func (p *ProjectRole) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
}

View File

@@ -354,6 +354,12 @@ func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *pr
func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) {
grant.OrgName = org.Name
for _, domain := range org.Domains {
if domain.Primary {
grant.OrgPrimaryDomain = domain.Domain
break
}
}
}
func (u *UserGrant) OnError(event *models.Event, err error) error {

View File

@@ -107,7 +107,7 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
case org_es_model.OrgMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence)
case org_es_model.OrgChanged:
err = m.updateOrgName(event)
return m.updateOrgName(event)
default:
return m.view.ProcessedUserMembershipSequence(event.Sequence)
}
@@ -178,7 +178,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
case proj_es_model.ProjectGrantMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence)
case proj_es_model.ProjectChanged:
err = m.updateProjectDisplayName(event)
return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved:
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence)
case proj_es_model.ProjectGrantRemoved:
@@ -227,6 +227,6 @@ func (m *UserMembership) processUser(event *models.Event) (err error) {
}
func (m *UserMembership) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgmember handler")
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler")
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
}

View File

@@ -135,6 +135,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
OrgViewProvider: view,
IDPProviderViewProvider: view,
LoginPolicyViewProvider: view,
UserGrantProvider: view,
IdGenerator: idGenerator,
PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
ExternalLoginCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration,
@@ -156,6 +157,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, au
View: view,
ProjectEvents: project,
},
eventstore.UserSessionRepo{
View: view,
},

View File

@@ -18,16 +18,28 @@ func (v *View) ApplicationByID(projectID, appID string) (*model.ApplicationView,
return view.ApplicationByID(v.Db, applicationTable, projectID, appID)
}
func (v *View) ApplicationsByProjectID(projectID string) ([]*model.ApplicationView, error) {
return view.ApplicationsByProjectID(v.Db, applicationTable, projectID)
}
func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, uint64, error) {
return view.SearchApplications(v.Db, applicationTable, request)
}
func (v *View) PutApplication(project *model.ApplicationView) error {
err := view.PutApplication(v.Db, applicationTable, project)
func (v *View) PutApplication(app *model.ApplicationView) error {
err := view.PutApplication(v.Db, applicationTable, app)
if err != nil {
return err
}
return v.ProcessedApplicationSequence(project.Sequence)
return v.ProcessedApplicationSequence(app.Sequence)
}
func (v *View) PutApplications(apps []*model.ApplicationView, sequence uint64) error {
err := view.PutApplications(v.Db, applicationTable, apps...)
if err != nil {
return err
}
return v.ProcessedApplicationSequence(sequence)
}
func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
@@ -38,6 +50,10 @@ func (v *View) DeleteApplication(appID string, eventSequence uint64) error {
return v.ProcessedApplicationSequence(eventSequence)
}
func (v *View) DeleteApplicationsByProjectID(projectID string) error {
return view.DeleteApplicationsByProjectID(v.Db, applicationTable, projectID)
}
func (v *View) GetLatestApplicationSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(applicationTable)
}
@@ -55,24 +71,7 @@ func (v *View) ProcessedApplicationFailedEvent(failedEvent *repository.FailedEve
}
func (v *View) ApplicationByClientID(_ context.Context, clientID string) (*model.ApplicationView, error) {
req := &proj_model.ApplicationSearchRequest{
Limit: 1,
Queries: []*proj_model.ApplicationSearchQuery{
{
Key: proj_model.AppSearchKeyOIDCClientID,
Method: global_model.SearchMethodEquals,
Value: clientID,
},
},
}
apps, count, err := view.SearchApplications(v.Db, applicationTable, req)
if err != nil {
return nil, errors.ThrowPreconditionFailed(err, "VIEW-sd6JQ", "cannot find client")
}
if count != 1 {
return nil, errors.ThrowPreconditionFailed(nil, "VIEW-dfw3as", "cannot find client")
}
return apps[0], nil
return view.ApplicationByOIDCClientID(v.Db, applicationTable, clientID)
}
func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string) ([]string, error) {
@@ -102,3 +101,27 @@ func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string)
}
return ids, nil
}
func (v *View) AppIDsFromProjectID(ctx context.Context, projectID string) ([]string, error) {
req := &proj_model.ApplicationSearchRequest{
Queries: []*proj_model.ApplicationSearchQuery{
{
Key: proj_model.AppSearchKeyProjectID,
Method: global_model.SearchMethodEquals,
Value: projectID,
},
},
}
apps, _, err := view.SearchApplications(v.Db, applicationTable, req)
if err != nil {
return nil, errors.ThrowPreconditionFailed(err, "VIEW-Gd24q", "cannot find applications")
}
ids := make([]string, 0, len(apps))
for _, app := range apps {
if !app.IsOIDC {
continue
}
ids = append(ids, app.OIDCClientID)
}
return ids, nil
}

View File

@@ -0,0 +1,68 @@
package view
import (
proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/project/repository/view"
"github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
)
const (
projectRoleTable = "auth.project_roles"
)
func (v *View) ProjectRoleByIDs(projectID, orgID, key string) (*model.ProjectRoleView, error) {
return view.ProjectRoleByIDs(v.Db, projectRoleTable, projectID, orgID, key)
}
func (v *View) ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error) {
return view.ProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
}
func (v *View) ResourceOwnerProjectRolesByKey(projectID, resourceowner, key string) ([]*model.ProjectRoleView, error) {
return view.ResourceOwnerProjectRolesByKey(v.Db, projectRoleTable, projectID, resourceowner, key)
}
func (v *View) ResourceOwnerProjectRoles(projectID, resourceowner string) ([]*model.ProjectRoleView, error) {
return view.ResourceOwnerProjectRoles(v.Db, projectRoleTable, projectID, resourceowner)
}
func (v *View) SearchProjectRoles(request *proj_model.ProjectRoleSearchRequest) ([]*model.ProjectRoleView, uint64, error) {
return view.SearchProjectRoles(v.Db, projectRoleTable, request)
}
func (v *View) PutProjectRole(project *model.ProjectRoleView) error {
err := view.PutProjectRole(v.Db, projectRoleTable, project)
if err != nil {
return err
}
return v.ProcessedProjectRoleSequence(project.Sequence)
}
func (v *View) DeleteProjectRole(projectID, orgID, key string, eventSequence uint64) error {
err := view.DeleteProjectRole(v.Db, projectRoleTable, projectID, orgID, key)
if err != nil {
return nil
}
return v.ProcessedProjectRoleSequence(eventSequence)
}
func (v *View) DeleteProjectRolesByProjectID(projectID string) error {
return view.DeleteProjectRolesByProjectID(v.Db, projectRoleTable, projectID)
}
func (v *View) GetLatestProjectRoleSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(projectRoleTable)
}
func (v *View) ProcessedProjectRoleSequence(eventSequence uint64) error {
return v.saveCurrentSequence(projectRoleTable, eventSequence)
}
func (v *View) GetLatestProjectRoleFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
return v.latestFailedEvent(projectRoleTable, sequence)
}
func (v *View) ProcessedProjectRoleFailedEvent(failedEvent *repository.FailedEvent) error {
return v.saveFailedEvent(failedEvent)
}

View File

@@ -36,7 +36,7 @@ func (v *View) PutUserMembership(membership *model.UserMembershipView, sequence
}
func (v *View) BulkPutUserMemberships(memberships []*model.UserMembershipView, sequence uint64) error {
err := view.PutUserMemberships(v.Db, userTable, memberships...)
err := view.PutUserMemberships(v.Db, userMembershipTable, memberships...)
if err != nil {
return err
}