Files
team/server/public/model/access_control_masking.go
Pablo VélezandGitHub 228112507a Mm 68846 masking from visual to canonical walker (#36772)
* MM-68846 - add canonical CEL AST masking walker and model resolver interface

* add canonical masking methods to PAP einterface and update mock

* Migrate app-layer masking to canonical CEL AST walker

* Remove Visual AST masking dead code and obsolete i18n key

* Update simulation masking tests to mock MaskExpressionForCaller

* reject persisted tokens and enforce merge shape match and add corresponding tests

* MM-68900 - abac masking add e2e back

* add missing config values and split the tests

* implement coderabbit feedback

* adjust timeout and disable button logic

* enhance masking logic and tests for access control policies

* refactor masking tests and database setup for improved field deletion handling

* Enhance error handling in TestMergeStoredPolicyExpressions to verify error ID and status code

* Refactor error handling in access control policy methods for clarity

* Refactor masking logic and improve clarity in access control methods

* Allow deny-all 'false' policies by dropping the redundant sentinel check in rejectMaskedTokens; add tests

* Add masking-related error messages and update test descriptions with tags

* Add error handling for uninitialized Policy Administration Point in access control
2026-06-16 17:09:11 +02:00

67 lines
2.5 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
// MaskingFieldAccessMode indicates how a property field's literal values are
// exposed to a given caller under attribute value masking rules.
type MaskingFieldAccessMode int
const (
MaskingFieldAccessUnknown MaskingFieldAccessMode = iota
// MaskingFieldAccessPublic means all values are visible to every caller.
MaskingFieldAccessPublic
// MaskingFieldAccessSharedOnly means the caller sees only values they themselves hold.
MaskingFieldAccessSharedOnly
// MaskingFieldAccessSourceOnly means values are never visible to callers.
MaskingFieldAccessSourceOnly
)
// MaskingTokenValue is the sentinel string written into masked CEL expressions
// to represent one or more hidden values without revealing their content.
const MaskingTokenValue = "--------"
// MaskingFieldInfo bundles per-field, per-caller visibility data for use by
// the canonical CEL AST masking walker.
type MaskingFieldInfo struct {
Access MaskingFieldAccessMode
// VisibleValues contains the literal values the caller may see.
// Populated for MaskingFieldAccessSharedOnly fields; nil for Public/SourceOnly/Unknown.
VisibleValues map[string]struct{}
}
// IsValueHidden reports whether the literal value lit is hidden from the caller
// under this field's access mode. It is the single source of truth for the
// per-value visibility decision shared by the masking, validation, and merge
// walkers.
//
// The masked-token placeholder (MaskingTokenValue) is never itself "hidden": it
// is a server-generated stand-in from a prior read response, not a real value.
// Unknown or unrecognised access modes fail closed (treated as hidden).
func (info *MaskingFieldInfo) IsValueHidden(lit string) bool {
if lit == MaskingTokenValue {
return false
}
switch info.Access {
case MaskingFieldAccessPublic:
return false
case MaskingFieldAccessSourceOnly:
return true
case MaskingFieldAccessSharedOnly:
_, visible := info.VisibleValues[lit]
return !visible
default:
return true
}
}
// MaskingFieldResolver answers field-visibility questions for a named property
// attribute (the suffix after "user.attributes.", e.g. "department").
//
// Implementations must be fail-closed: return a non-nil error for any lookup
// that cannot be proven safe. The walker treats any resolver error as a
// reason to mask all literals for that field.
type MaskingFieldResolver interface {
Resolve(fieldName string) (*MaskingFieldInfo, error)
}