mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 04:37:31 +00:00
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:
@@ -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
|
||||
}
|
||||
|
@@ -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,
|
||||
|
21
internal/auth/repository/eventsourcing/eventstore/project.go
Normal file
21
internal/auth/repository/eventsourcing/eventstore/project.go
Normal 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
|
||||
}
|
@@ -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)
|
||||
}
|
||||
|
@@ -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},
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
}
|
@@ -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 {
|
||||
|
@@ -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)
|
||||
}
|
||||
|
@@ -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,
|
||||
},
|
||||
|
@@ -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
|
||||
}
|
||||
|
68
internal/auth/repository/eventsourcing/view/project_role.go
Normal file
68
internal/auth/repository/eventsourcing/view/project_role.go
Normal 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)
|
||||
}
|
@@ -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
|
||||
}
|
||||
|
9
internal/auth/repository/project.go
Normal file
9
internal/auth/repository/project.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/project/model"
|
||||
)
|
||||
|
||||
type ProjectRepository interface {
|
||||
ProjectRolesByProjectID(projectID string) ([]*model.ProjectRoleView, error)
|
||||
}
|
@@ -10,6 +10,7 @@ type Repository interface {
|
||||
AuthRequestRepository
|
||||
TokenRepository
|
||||
ApplicationRepository
|
||||
ProjectRepository
|
||||
KeyRepository
|
||||
UserSessionRepository
|
||||
UserGrantRepository
|
||||
|
Reference in New Issue
Block a user