[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>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
4b445cbf16
Коммит
a344b3225b
293
server/channels/app/access_control.go
Обычный файл
293
server/channels/app/access_control.go
Обычный файл
@@ -0,0 +1,293 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost/server/public/model"
|
||||
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
||||
"github.com/mattermost/mattermost/server/public/shared/request"
|
||||
)
|
||||
|
||||
func (a *App) GetChannelsForPolicy(rctx request.CTX, policyID string, cursor model.AccessControlPolicyCursor, limit int) ([]*model.ChannelWithTeamData, int64, *model.AppError) {
|
||||
policy, appErr := a.GetAccessControlPolicy(rctx, policyID)
|
||||
if appErr != nil {
|
||||
return nil, 0, appErr
|
||||
}
|
||||
|
||||
switch policy.Type {
|
||||
case model.AccessControlPolicyTypeParent:
|
||||
policies, total, err := a.Srv().Store().AccessControlPolicy().SearchPolicies(rctx, model.AccessControlPolicySearch{
|
||||
Type: model.AccessControlPolicyTypeChannel,
|
||||
ParentID: policyID,
|
||||
Cursor: cursor,
|
||||
Limit: limit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, model.NewAppError("GetChannelsForPolicy", "app.pap.get_all_access_control_policies.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
channelIDs := make([]string, 0, len(policies))
|
||||
|
||||
for _, p := range policies {
|
||||
channelIDs = append(channelIDs, p.ID)
|
||||
}
|
||||
|
||||
chs, err := a.Srv().Store().Channel().GetChannelsWithTeamDataByIds(channelIDs, true)
|
||||
if err != nil {
|
||||
return nil, 0, model.NewAppError("GetChannelsForPolicy", "app.pap.get_all_access_control_policies.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return chs, total, nil
|
||||
case model.AccessControlPolicyTypeChannel:
|
||||
chs, err := a.Srv().Store().Channel().GetChannelsWithTeamDataByIds([]string{policyID}, true)
|
||||
if err != nil {
|
||||
return nil, 0, model.NewAppError("GetChannelsForPolicy", "app.pap.get_all_access_control_policies.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
total := int64(len(chs))
|
||||
return chs, total, nil
|
||||
default:
|
||||
return nil, 0, model.NewAppError("GetChannelsForPolicy", "app.pap.get_all_access_control_policies.app_error", nil, "Invalid policy type", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) GetAccessControlPolicy(rctx request.CTX, id string) (*model.AccessControlPolicy, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("GetPolicy", "app.pap.get_policy.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
policy, appErr := acs.GetPolicy(rctx, id)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func (a *App) CreateOrUpdateAccessControlPolicy(rctx request.CTX, policy *model.AccessControlPolicy) (*model.AccessControlPolicy, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("CreateAccessControlPolicy", "app.pap.create_access_control_policy.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if policy.ID == "" {
|
||||
policy.ID = model.NewId()
|
||||
}
|
||||
|
||||
var appErr *model.AppError
|
||||
policy, appErr = acs.SavePolicy(rctx, policy)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func (a *App) DeleteAccessControlPolicy(rctx request.CTX, id string) *model.AppError {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return model.NewAppError("DeleteAccessControlPolicy", "app.pap.delete_access_control_policy.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
appErr := acs.DeletePolicy(rctx, id)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) CheckExpression(rctx request.CTX, expression string) ([]model.CELExpressionError, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("CheckExpression", "app.pap.check_expression.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
errs, appErr := acs.CheckExpression(rctx, expression)
|
||||
if appErr != nil {
|
||||
return nil, model.NewAppError("CheckExpression", "app.pap.check_expression.app_error", nil, appErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return errs, nil
|
||||
}
|
||||
|
||||
func (a *App) TestExpression(rctx request.CTX, expression string, opts model.SubjectSearchOptions) ([]*model.User, int64, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, 0, model.NewAppError("TestExpression", "app.pap.check_expression.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
res, count, err := acs.QueryUsersForExpression(rctx, expression, opts)
|
||||
if err != nil {
|
||||
return nil, 0, model.NewAppError("TestExpression", "app.pap.check_expression.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return res, count, nil
|
||||
}
|
||||
|
||||
func (a *App) AssignAccessControlPolicyToChannels(rctx request.CTX, parentID string, channelIDs []string) ([]*model.AccessControlPolicy, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("AssignAccessControlPolicyToChannels", "app.pap.assign_access_control_policy_to_channels.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
policy, appErr := a.GetAccessControlPolicy(rctx, parentID)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
if policy.Type != model.AccessControlPolicyTypeParent {
|
||||
return nil, model.NewAppError("AssignAccessControlPolicyToChannels", "app.pap.assign_access_control_policy_to_channels.app_error", nil, "Policy is not of type parent", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
channels, err := a.GetChannels(rctx, channelIDs)
|
||||
if err != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
policies := make([]*model.AccessControlPolicy, 0, len(channelIDs))
|
||||
for _, channel := range channels {
|
||||
if channel.Type != model.ChannelTypePrivate || channel.IsGroupConstrained() {
|
||||
return nil, model.NewAppError("AssignAccessControlPolicyToChannels", "app.pap.assign_access_control_policy_to_channels.app_error", nil, "Channel is not of type private", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if channel.IsShared() {
|
||||
return nil, model.NewAppError("AssignAccessControlPolicyToChannels", "app.pap.assign_access_control_policy_to_channels.app_error", nil, "Channel is shared", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
newPolicy, appErr := policy.Inherit(channel.Id, model.AccessControlPolicyTypeChannel)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
newPolicy, appErr = acs.SavePolicy(rctx, newPolicy)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
policies = append(policies, newPolicy)
|
||||
}
|
||||
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func (a *App) UnAssignPoliciesFromChannels(rctx request.CTX, policyID string, channelIDs []string) *model.AppError {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return model.NewAppError("UnAssignPoliciesFromChannels", "app.pap.unassign_access_control_policy_from_channels.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
cps, _, err := a.Srv().Store().AccessControlPolicy().SearchPolicies(rctx, model.AccessControlPolicySearch{
|
||||
Type: model.AccessControlPolicyTypeChannel,
|
||||
ParentID: policyID,
|
||||
})
|
||||
if err != nil {
|
||||
return model.NewAppError("UnAssignPoliciesFromChannels", "app.pap.unassign_access_control_policy_from_channels.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
childPolicies := make(map[string]bool)
|
||||
for _, p := range cps {
|
||||
childPolicies[p.ID] = true
|
||||
}
|
||||
|
||||
for _, channelID := range channelIDs {
|
||||
if _, ok := childPolicies[channelID]; !ok {
|
||||
mlog.Warn("Policy is not assigned to the parent policy", mlog.String("channel_id", channelID), mlog.String("parent_policy_id", policyID))
|
||||
continue
|
||||
}
|
||||
|
||||
appErr := acs.DeletePolicy(rctx, channelID)
|
||||
if appErr != nil {
|
||||
return appErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) SearchAccessControlPolicies(rctx request.CTX, opts model.AccessControlPolicySearch) ([]*model.AccessControlPolicy, int64, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, 0, model.NewAppError("SearchAccessControlPolicies", "app.pap.search_access_control_policies.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
policies, total, err := a.Srv().Store().AccessControlPolicy().SearchPolicies(rctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, model.NewAppError("SearchAccessControlPolicies", "app.pap.search_access_control_policies.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
for i, policy := range policies {
|
||||
if policy.Type != model.AccessControlPolicyTypeParent {
|
||||
continue
|
||||
}
|
||||
|
||||
normlizedPolicy, appErr := acs.NormalizePolicy(rctx, policy)
|
||||
if appErr != nil {
|
||||
mlog.Error("Failed to normalize policy", mlog.String("policy_id", policy.ID), mlog.Err(appErr))
|
||||
continue
|
||||
}
|
||||
policies[i] = normlizedPolicy
|
||||
}
|
||||
|
||||
return policies, total, nil
|
||||
}
|
||||
|
||||
func (a *App) GetAccessControlPolicyAttributes(rctx request.CTX, channelID string, action string) (map[string][]string, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("GetChannelAccessControlAttributes", "app.pap.get_channel_access_control_attributes.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
attributes, appErr := acs.GetPolicyRuleAttributes(rctx, channelID, action)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return attributes, nil
|
||||
}
|
||||
|
||||
func (a *App) GetAccessControlFieldsAutocomplete(rctx request.CTX, after string, limit int) ([]*model.PropertyField, *model.AppError) {
|
||||
cpaGroupID, err := a.CpaGroupID()
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetAccessControlAutoComplete", "app.pap.get_access_control_auto_complete.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
fields, err := a.Srv().Store().PropertyField().SearchPropertyFields(model.PropertyFieldSearchOpts{
|
||||
GroupID: cpaGroupID,
|
||||
Cursor: model.PropertyFieldSearchCursor{
|
||||
PropertyFieldID: after,
|
||||
CreateAt: 1,
|
||||
},
|
||||
PerPage: limit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetAccessControlAutoComplete", "app.pap.get_access_control_auto_complete.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
func (a *App) UpdateAccessControlPolicyActive(rctx request.CTX, policyID string, active bool) *model.AppError {
|
||||
_, err := a.Srv().Store().AccessControlPolicy().SetActiveStatus(rctx, policyID, active)
|
||||
if err != nil {
|
||||
return model.NewAppError("UpdateAccessControlPolicyActive", "app.pap.update_access_control_policy_active.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) ExpressionToVisualAST(rctx request.CTX, expression string) (*model.VisualExpression, *model.AppError) {
|
||||
acs := a.Srv().ch.AccessControl
|
||||
if acs == nil {
|
||||
return nil, model.NewAppError("ExpressionToVisualAST", "app.pap.expression_to_visual_ast.app_error", nil, "Policy Administration Point is not initialized", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
visualAST, appErr := acs.ExpressionToVisualAST(rctx, expression)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
|
||||
return visualAST, nil
|
||||
}
|
||||
Ссылка в новой задаче
Block a user