[MM-61756] Attribute Based Access Control - Phase 1 (#30785)

Attribute Based Access Control - Base
* MM-63662

* MM-63919

* MM-63954

* MM-63955 

* MM-63425

* MM-63426

* MM-63458

* MM-63459

* MM-63603

* MM-63845

* MM-64146

* MM-64199

* MM-64201

* MM-64233

* MM-64247

* MM-64268

---------

Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>
Co-authored-by: Pablo Andrés Vélez Vidal <pablovv2012@gmail.com>
Co-authored-by: abhijit-singh <abhijitsingh0702@gmail.com>
Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
Этот коммит содержится в:
Ibrahim Serdar Acikgoz
2025-05-15 11:33:08 +02:00
коммит произвёл GitHub
родитель 4b445cbf16
Коммит a344b3225b
156 изменённых файлов: 14382 добавлений и 621 удалений

12
server/einterfaces/access_control.go Обычный файл
Просмотреть файл

@@ -0,0 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package einterfaces
// AccessControlServiceInterface is the interface that provides access control
// services. It combines the PolicyAdministrationPointInterface and
// PolicyDecisionPointInterface interfaces to provide a complete access control solution.
type AccessControlServiceInterface interface {
PolicyAdministrationPointInterface
PolicyDecisionPointInterface
}

13
server/einterfaces/jobs/access_control.go Обычный файл
Просмотреть файл

@@ -0,0 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package jobs
import (
"github.com/mattermost/mattermost/server/public/model"
)
type AccessControlSyncJobInterface interface {
MakeWorker() model.Worker
MakeScheduler() Scheduler
}

Просмотреть файл

@@ -135,7 +135,7 @@ type MetricsInterface interface {
ObserveDesktopCpuUsage(platform, version, process string, usage float64)
ObserveDesktopMemoryUsage(platform, version, process string, usage float64)
ObserveAccessControlEngineInitDuration(value float64)
ObserveAccessControlSearchQueryDuration(value float64)
ObserveAccessControlExpressionCompileDuration(value float64)
ObserveAccessControlEvaluateDuration(value float64)
IncrementAccessControlCacheInvalidation()

Просмотреть файл

@@ -0,0 +1,402 @@
// Code generated by mockery v2.42.2. DO NOT EDIT.
// Regenerate this file using `make einterfaces-mocks`.
package mocks
import (
model "github.com/mattermost/mattermost/server/public/model"
request "github.com/mattermost/mattermost/server/public/shared/request"
mock "github.com/stretchr/testify/mock"
)
// AccessControlServiceInterface is an autogenerated mock type for the AccessControlServiceInterface type
type AccessControlServiceInterface struct {
mock.Mock
}
// AccessEvaluation provides a mock function with given fields: rctx, accessRequest
func (_m *AccessControlServiceInterface) AccessEvaluation(rctx request.CTX, accessRequest model.AccessRequest) (model.AccessDecision, *model.AppError) {
ret := _m.Called(rctx, accessRequest)
if len(ret) == 0 {
panic("no return value specified for AccessEvaluation")
}
var r0 model.AccessDecision
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) (model.AccessDecision, *model.AppError)); ok {
return rf(rctx, accessRequest)
}
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) model.AccessDecision); ok {
r0 = rf(rctx, accessRequest)
} else {
r0 = ret.Get(0).(model.AccessDecision)
}
if rf, ok := ret.Get(1).(func(request.CTX, model.AccessRequest) *model.AppError); ok {
r1 = rf(rctx, accessRequest)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// CheckExpression provides a mock function with given fields: rctx, expression
func (_m *AccessControlServiceInterface) CheckExpression(rctx request.CTX, expression string) ([]model.CELExpressionError, *model.AppError) {
ret := _m.Called(rctx, expression)
if len(ret) == 0 {
panic("no return value specified for CheckExpression")
}
var r0 []model.CELExpressionError
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) ([]model.CELExpressionError, *model.AppError)); ok {
return rf(rctx, expression)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) []model.CELExpressionError); ok {
r0 = rf(rctx, expression)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]model.CELExpressionError)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, expression)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// DeletePolicy provides a mock function with given fields: rctx, id
func (_m *AccessControlServiceInterface) DeletePolicy(rctx request.CTX, id string) *model.AppError {
ret := _m.Called(rctx, id)
if len(ret) == 0 {
panic("no return value specified for DeletePolicy")
}
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AppError); ok {
r0 = rf(rctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// ExpressionToVisualAST provides a mock function with given fields: rctx, expression
func (_m *AccessControlServiceInterface) ExpressionToVisualAST(rctx request.CTX, expression string) (*model.VisualExpression, *model.AppError) {
ret := _m.Called(rctx, expression)
if len(ret) == 0 {
panic("no return value specified for ExpressionToVisualAST")
}
var r0 *model.VisualExpression
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.VisualExpression, *model.AppError)); ok {
return rf(rctx, expression)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.VisualExpression); ok {
r0 = rf(rctx, expression)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.VisualExpression)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, expression)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetChannelMembersToRemove provides a mock function with given fields: rctx, channelID
func (_m *AccessControlServiceInterface) GetChannelMembersToRemove(rctx request.CTX, channelID string) ([]*model.ChannelMember, *model.AppError) {
ret := _m.Called(rctx, channelID)
if len(ret) == 0 {
panic("no return value specified for GetChannelMembersToRemove")
}
var r0 []*model.ChannelMember
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) ([]*model.ChannelMember, *model.AppError)); ok {
return rf(rctx, channelID)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) []*model.ChannelMember); ok {
r0 = rf(rctx, channelID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.ChannelMember)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, channelID)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPolicy provides a mock function with given fields: rctx, id
func (_m *AccessControlServiceInterface) GetPolicy(rctx request.CTX, id string) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, id)
if len(ret) == 0 {
panic("no return value specified for GetPolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, id)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AccessControlPolicy); ok {
r0 = rf(rctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, id)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPolicyRuleAttributes provides a mock function with given fields: rctx, policyID, action
func (_m *AccessControlServiceInterface) GetPolicyRuleAttributes(rctx request.CTX, policyID string, action string) (map[string][]string, *model.AppError) {
ret := _m.Called(rctx, policyID, action)
if len(ret) == 0 {
panic("no return value specified for GetPolicyRuleAttributes")
}
var r0 map[string][]string
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, string) (map[string][]string, *model.AppError)); ok {
return rf(rctx, policyID, action)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, string) map[string][]string); ok {
r0 = rf(rctx, policyID, action)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string][]string)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, string) *model.AppError); ok {
r1 = rf(rctx, policyID, action)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// Init provides a mock function with given fields: rctx
func (_m *AccessControlServiceInterface) Init(rctx request.CTX) *model.AppError {
ret := _m.Called(rctx)
if len(ret) == 0 {
panic("no return value specified for Init")
}
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX) *model.AppError); ok {
r0 = rf(rctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// NormalizePolicy provides a mock function with given fields: rctx, policy
func (_m *AccessControlServiceInterface) NormalizePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, policy)
if len(ret) == 0 {
panic("no return value specified for NormalizePolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, policy)
}
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) *model.AccessControlPolicy); ok {
r0 = rf(rctx, policy)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, *model.AccessControlPolicy) *model.AppError); ok {
r1 = rf(rctx, policy)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// QueryUsersForExpression provides a mock function with given fields: rctx, expression, opts
func (_m *AccessControlServiceInterface) QueryUsersForExpression(rctx request.CTX, expression string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError) {
ret := _m.Called(rctx, expression, opts)
if len(ret) == 0 {
panic("no return value specified for QueryUsersForExpression")
}
var r0 []*model.User
var r1 int64
var r2 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)); ok {
return rf(rctx, expression, opts)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, model.SubjectSearchOptions) []*model.User); ok {
r0 = rf(rctx, expression, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, model.SubjectSearchOptions) int64); ok {
r1 = rf(rctx, expression, opts)
} else {
r1 = ret.Get(1).(int64)
}
if rf, ok := ret.Get(2).(func(request.CTX, string, model.SubjectSearchOptions) *model.AppError); ok {
r2 = rf(rctx, expression, opts)
} else {
if ret.Get(2) != nil {
r2 = ret.Get(2).(*model.AppError)
}
}
return r0, r1, r2
}
// QueryUsersForResource provides a mock function with given fields: rctx, resourceID, action, opts
func (_m *AccessControlServiceInterface) QueryUsersForResource(rctx request.CTX, resourceID string, action string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError) {
ret := _m.Called(rctx, resourceID, action, opts)
if len(ret) == 0 {
panic("no return value specified for QueryUsersForResource")
}
var r0 []*model.User
var r1 int64
var r2 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, string, model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)); ok {
return rf(rctx, resourceID, action, opts)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, string, model.SubjectSearchOptions) []*model.User); ok {
r0 = rf(rctx, resourceID, action, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, string, model.SubjectSearchOptions) int64); ok {
r1 = rf(rctx, resourceID, action, opts)
} else {
r1 = ret.Get(1).(int64)
}
if rf, ok := ret.Get(2).(func(request.CTX, string, string, model.SubjectSearchOptions) *model.AppError); ok {
r2 = rf(rctx, resourceID, action, opts)
} else {
if ret.Get(2) != nil {
r2 = ret.Get(2).(*model.AppError)
}
}
return r0, r1, r2
}
// SavePolicy provides a mock function with given fields: rctx, policy
func (_m *AccessControlServiceInterface) SavePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, policy)
if len(ret) == 0 {
panic("no return value specified for SavePolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, policy)
}
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) *model.AccessControlPolicy); ok {
r0 = rf(rctx, policy)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, *model.AccessControlPolicy) *model.AppError); ok {
r1 = rf(rctx, policy)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// NewAccessControlServiceInterface creates a new instance of AccessControlServiceInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewAccessControlServiceInterface(t interface {
mock.TestingT
Cleanup(func())
}) *AccessControlServiceInterface {
mock := &AccessControlServiceInterface{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

Просмотреть файл

@@ -0,0 +1,71 @@
// Code generated by mockery v2.42.2. DO NOT EDIT.
// Regenerate this file using `make einterfaces-mocks`.
package mocks
import (
jobs "github.com/mattermost/mattermost/server/v8/einterfaces/jobs"
mock "github.com/stretchr/testify/mock"
model "github.com/mattermost/mattermost/server/public/model"
)
// AccessControlSyncJobInterface is an autogenerated mock type for the AccessControlSyncJobInterface type
type AccessControlSyncJobInterface struct {
mock.Mock
}
// MakeScheduler provides a mock function with given fields:
func (_m *AccessControlSyncJobInterface) MakeScheduler() jobs.Scheduler {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for MakeScheduler")
}
var r0 jobs.Scheduler
if rf, ok := ret.Get(0).(func() jobs.Scheduler); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(jobs.Scheduler)
}
}
return r0
}
// MakeWorker provides a mock function with given fields:
func (_m *AccessControlSyncJobInterface) MakeWorker() model.Worker {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for MakeWorker")
}
var r0 model.Worker
if rf, ok := ret.Get(0).(func() model.Worker); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(model.Worker)
}
}
return r0
}
// NewAccessControlSyncJobInterface creates a new instance of AccessControlSyncJobInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewAccessControlSyncJobInterface(t interface {
mock.TestingT
Cleanup(func())
}) *AccessControlSyncJobInterface {
mock := &AccessControlSyncJobInterface{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

Просмотреть файл

@@ -308,11 +308,6 @@ func (_m *MetricsInterface) ObserveAPIEndpointDuration(endpoint string, method s
_m.Called(endpoint, method, statusCode, originClient, pageLoadContext, elapsed)
}
// ObserveAccessControlEngineInitDuration provides a mock function with given fields: value
func (_m *MetricsInterface) ObserveAccessControlEngineInitDuration(value float64) {
_m.Called(value)
}
// ObserveAccessControlEvaluateDuration provides a mock function with given fields: value
func (_m *MetricsInterface) ObserveAccessControlEvaluateDuration(value float64) {
_m.Called(value)
@@ -323,6 +318,11 @@ func (_m *MetricsInterface) ObserveAccessControlExpressionCompileDuration(value
_m.Called(value)
}
// ObserveAccessControlSearchQueryDuration provides a mock function with given fields: value
func (_m *MetricsInterface) ObserveAccessControlSearchQueryDuration(value float64) {
_m.Called(value)
}
// ObserveClientChannelSwitchDuration provides a mock function with given fields: platform, agent, fresh, userID, elapsed
func (_m *MetricsInterface) ObserveClientChannelSwitchDuration(platform string, agent string, fresh string, userID string, elapsed float64) {
_m.Called(platform, agent, fresh, userID, elapsed)

Просмотреть файл

@@ -0,0 +1,372 @@
// Code generated by mockery v2.42.2. DO NOT EDIT.
// Regenerate this file using `make einterfaces-mocks`.
package mocks
import (
model "github.com/mattermost/mattermost/server/public/model"
request "github.com/mattermost/mattermost/server/public/shared/request"
mock "github.com/stretchr/testify/mock"
)
// PolicyAdministrationPointInterface is an autogenerated mock type for the PolicyAdministrationPointInterface type
type PolicyAdministrationPointInterface struct {
mock.Mock
}
// CheckExpression provides a mock function with given fields: rctx, expression
func (_m *PolicyAdministrationPointInterface) CheckExpression(rctx request.CTX, expression string) ([]model.CELExpressionError, *model.AppError) {
ret := _m.Called(rctx, expression)
if len(ret) == 0 {
panic("no return value specified for CheckExpression")
}
var r0 []model.CELExpressionError
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) ([]model.CELExpressionError, *model.AppError)); ok {
return rf(rctx, expression)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) []model.CELExpressionError); ok {
r0 = rf(rctx, expression)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]model.CELExpressionError)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, expression)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// DeletePolicy provides a mock function with given fields: rctx, id
func (_m *PolicyAdministrationPointInterface) DeletePolicy(rctx request.CTX, id string) *model.AppError {
ret := _m.Called(rctx, id)
if len(ret) == 0 {
panic("no return value specified for DeletePolicy")
}
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AppError); ok {
r0 = rf(rctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// ExpressionToVisualAST provides a mock function with given fields: rctx, expression
func (_m *PolicyAdministrationPointInterface) ExpressionToVisualAST(rctx request.CTX, expression string) (*model.VisualExpression, *model.AppError) {
ret := _m.Called(rctx, expression)
if len(ret) == 0 {
panic("no return value specified for ExpressionToVisualAST")
}
var r0 *model.VisualExpression
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.VisualExpression, *model.AppError)); ok {
return rf(rctx, expression)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.VisualExpression); ok {
r0 = rf(rctx, expression)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.VisualExpression)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, expression)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetChannelMembersToRemove provides a mock function with given fields: rctx, channelID
func (_m *PolicyAdministrationPointInterface) GetChannelMembersToRemove(rctx request.CTX, channelID string) ([]*model.ChannelMember, *model.AppError) {
ret := _m.Called(rctx, channelID)
if len(ret) == 0 {
panic("no return value specified for GetChannelMembersToRemove")
}
var r0 []*model.ChannelMember
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) ([]*model.ChannelMember, *model.AppError)); ok {
return rf(rctx, channelID)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) []*model.ChannelMember); ok {
r0 = rf(rctx, channelID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.ChannelMember)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, channelID)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPolicy provides a mock function with given fields: rctx, id
func (_m *PolicyAdministrationPointInterface) GetPolicy(rctx request.CTX, id string) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, id)
if len(ret) == 0 {
panic("no return value specified for GetPolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, id)
}
if rf, ok := ret.Get(0).(func(request.CTX, string) *model.AccessControlPolicy); ok {
r0 = rf(rctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string) *model.AppError); ok {
r1 = rf(rctx, id)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPolicyRuleAttributes provides a mock function with given fields: rctx, policyID, action
func (_m *PolicyAdministrationPointInterface) GetPolicyRuleAttributes(rctx request.CTX, policyID string, action string) (map[string][]string, *model.AppError) {
ret := _m.Called(rctx, policyID, action)
if len(ret) == 0 {
panic("no return value specified for GetPolicyRuleAttributes")
}
var r0 map[string][]string
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, string) (map[string][]string, *model.AppError)); ok {
return rf(rctx, policyID, action)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, string) map[string][]string); ok {
r0 = rf(rctx, policyID, action)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string][]string)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, string) *model.AppError); ok {
r1 = rf(rctx, policyID, action)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// Init provides a mock function with given fields: rctx
func (_m *PolicyAdministrationPointInterface) Init(rctx request.CTX) *model.AppError {
ret := _m.Called(rctx)
if len(ret) == 0 {
panic("no return value specified for Init")
}
var r0 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX) *model.AppError); ok {
r0 = rf(rctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AppError)
}
}
return r0
}
// NormalizePolicy provides a mock function with given fields: rctx, policy
func (_m *PolicyAdministrationPointInterface) NormalizePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, policy)
if len(ret) == 0 {
panic("no return value specified for NormalizePolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, policy)
}
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) *model.AccessControlPolicy); ok {
r0 = rf(rctx, policy)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, *model.AccessControlPolicy) *model.AppError); ok {
r1 = rf(rctx, policy)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// QueryUsersForExpression provides a mock function with given fields: rctx, expression, opts
func (_m *PolicyAdministrationPointInterface) QueryUsersForExpression(rctx request.CTX, expression string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError) {
ret := _m.Called(rctx, expression, opts)
if len(ret) == 0 {
panic("no return value specified for QueryUsersForExpression")
}
var r0 []*model.User
var r1 int64
var r2 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)); ok {
return rf(rctx, expression, opts)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, model.SubjectSearchOptions) []*model.User); ok {
r0 = rf(rctx, expression, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, model.SubjectSearchOptions) int64); ok {
r1 = rf(rctx, expression, opts)
} else {
r1 = ret.Get(1).(int64)
}
if rf, ok := ret.Get(2).(func(request.CTX, string, model.SubjectSearchOptions) *model.AppError); ok {
r2 = rf(rctx, expression, opts)
} else {
if ret.Get(2) != nil {
r2 = ret.Get(2).(*model.AppError)
}
}
return r0, r1, r2
}
// QueryUsersForResource provides a mock function with given fields: rctx, resourceID, action, opts
func (_m *PolicyAdministrationPointInterface) QueryUsersForResource(rctx request.CTX, resourceID string, action string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError) {
ret := _m.Called(rctx, resourceID, action, opts)
if len(ret) == 0 {
panic("no return value specified for QueryUsersForResource")
}
var r0 []*model.User
var r1 int64
var r2 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, string, string, model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)); ok {
return rf(rctx, resourceID, action, opts)
}
if rf, ok := ret.Get(0).(func(request.CTX, string, string, model.SubjectSearchOptions) []*model.User); ok {
r0 = rf(rctx, resourceID, action, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, string, string, model.SubjectSearchOptions) int64); ok {
r1 = rf(rctx, resourceID, action, opts)
} else {
r1 = ret.Get(1).(int64)
}
if rf, ok := ret.Get(2).(func(request.CTX, string, string, model.SubjectSearchOptions) *model.AppError); ok {
r2 = rf(rctx, resourceID, action, opts)
} else {
if ret.Get(2) != nil {
r2 = ret.Get(2).(*model.AppError)
}
}
return r0, r1, r2
}
// SavePolicy provides a mock function with given fields: rctx, policy
func (_m *PolicyAdministrationPointInterface) SavePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError) {
ret := _m.Called(rctx, policy)
if len(ret) == 0 {
panic("no return value specified for SavePolicy")
}
var r0 *model.AccessControlPolicy
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)); ok {
return rf(rctx, policy)
}
if rf, ok := ret.Get(0).(func(request.CTX, *model.AccessControlPolicy) *model.AccessControlPolicy); ok {
r0 = rf(rctx, policy)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessControlPolicy)
}
}
if rf, ok := ret.Get(1).(func(request.CTX, *model.AccessControlPolicy) *model.AppError); ok {
r1 = rf(rctx, policy)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// NewPolicyAdministrationPointInterface creates a new instance of PolicyAdministrationPointInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewPolicyAdministrationPointInterface(t interface {
mock.TestingT
Cleanup(func())
}) *PolicyAdministrationPointInterface {
mock := &PolicyAdministrationPointInterface{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

Просмотреть файл

@@ -16,24 +16,22 @@ type PolicyDecisionPointInterface struct {
}
// AccessEvaluation provides a mock function with given fields: rctx, accessRequest
func (_m *PolicyDecisionPointInterface) AccessEvaluation(rctx request.CTX, accessRequest model.AccessRequest) (*model.AccessDecision, *model.AppError) {
func (_m *PolicyDecisionPointInterface) AccessEvaluation(rctx request.CTX, accessRequest model.AccessRequest) (model.AccessDecision, *model.AppError) {
ret := _m.Called(rctx, accessRequest)
if len(ret) == 0 {
panic("no return value specified for AccessEvaluation")
}
var r0 *model.AccessDecision
var r0 model.AccessDecision
var r1 *model.AppError
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) (*model.AccessDecision, *model.AppError)); ok {
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) (model.AccessDecision, *model.AppError)); ok {
return rf(rctx, accessRequest)
}
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) *model.AccessDecision); ok {
if rf, ok := ret.Get(0).(func(request.CTX, model.AccessRequest) model.AccessDecision); ok {
r0 = rf(rctx, accessRequest)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.AccessDecision)
}
r0 = ret.Get(0).(model.AccessDecision)
}
if rf, ok := ret.Get(1).(func(request.CTX, model.AccessRequest) *model.AppError); ok {

42
server/einterfaces/pap.go Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package einterfaces
import (
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/request"
)
// PolicyAdministrationPointInterface is the service that manages access control policies.
// It is responsible for creating, updating, and deleting policies.
// Also, it provides methods to check the validity of expressions and to retrieve policies.
type PolicyAdministrationPointInterface interface {
// Init initializes the policy administration point and intiates the CEL engine.
// It is an idempotent operation, meaning that it can be called multiple times.
Init(rctx request.CTX) *model.AppError
// GetPolicyRuleAttributes retrieves the attributes of the given policy.
// It returns a map of attribute names to their values for given action.
GetPolicyRuleAttributes(rctx request.CTX, policyID string, action string) (map[string][]string, *model.AppError)
// CheckExpression checks the validity of the given expression using the CEL engine.
// It returns a list of CELExpressionError if the expression is invalid.
// If the expression is valid, it returns an empty list.
CheckExpression(rctx request.CTX, expression string) ([]model.CELExpressionError, *model.AppError)
// ExpressionToVisualAST converts the given expression to a visual AST.
ExpressionToVisualAST(rctx request.CTX, expression string) (*model.VisualExpression, *model.AppError)
// NormalizePolicy normalizes the given policy by restoring ids back to names.
NormalizePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)
// QueryUsersForExpression evaluates the given expression using the CEL engine.
// It returns a list of users that match the expression.
QueryUsersForExpression(rctx request.CTX, expression string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)
// QueryUsersForResource evaluates finds the users match to the resource.
QueryUsersForResource(rctx request.CTX, resourceID, action string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError)
// GetChannelMembersToRemove retrieves the channel members that need to be removed from the given channel.
GetChannelMembersToRemove(rctx request.CTX, channelID string) ([]*model.ChannelMember, *model.AppError)
// SavePolicy saves the given access control policy.
SavePolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError)
// GetPolicy retrieves the access control policy with the given ID.
GetPolicy(rctx request.CTX, id string) (*model.AccessControlPolicy, *model.AppError)
// DeletePolicy deletes the access control policy with the given ID.
DeletePolicy(rctx request.CTX, id string) *model.AppError
}

Просмотреть файл

@@ -12,5 +12,5 @@ import (
// using the OpenID Auth API spec. It determines whether a subject can perform
// an action on a resource based on the resource policy.
type PolicyDecisionPointInterface interface {
AccessEvaluation(rctx request.CTX, accessRequest model.AccessRequest) (*model.AccessDecision, *model.AppError)
AccessEvaluation(rctx request.CTX, accessRequest model.AccessRequest) (model.AccessDecision, *model.AppError)
}