| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768 |
- package policy_engine
- import (
- "fmt"
- "net"
- "reflect"
- "strconv"
- "strings"
- "sync"
- "time"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- )
- // LRUNode represents a node in the doubly-linked list for efficient LRU operations
- type LRUNode struct {
- key string
- value []string
- prev *LRUNode
- next *LRUNode
- }
- // NormalizedValueCache provides size-limited caching for normalized values with efficient LRU eviction
- type NormalizedValueCache struct {
- mu sync.RWMutex
- cache map[string]*LRUNode
- maxSize int
- head *LRUNode // Most recently used
- tail *LRUNode // Least recently used
- }
- // NewNormalizedValueCache creates a new normalized value cache with configurable size
- func NewNormalizedValueCache(maxSize int) *NormalizedValueCache {
- if maxSize <= 0 {
- maxSize = 1000 // Default size
- }
- // Create dummy head and tail nodes for easier list manipulation
- head := &LRUNode{}
- tail := &LRUNode{}
- head.next = tail
- tail.prev = head
- return &NormalizedValueCache{
- cache: make(map[string]*LRUNode),
- maxSize: maxSize,
- head: head,
- tail: tail,
- }
- }
- // Get retrieves a cached value and updates access order in O(1) time
- func (c *NormalizedValueCache) Get(key string) ([]string, bool) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if node, exists := c.cache[key]; exists {
- // Move to head (most recently used) - O(1) operation
- c.moveToHead(node)
- return node.value, true
- }
- return nil, false
- }
- // Set stores a value in the cache with size limit enforcement in O(1) time
- func (c *NormalizedValueCache) Set(key string, value []string) {
- c.mu.Lock()
- defer c.mu.Unlock()
- if node, exists := c.cache[key]; exists {
- // Update existing node and move to head
- node.value = value
- c.moveToHead(node)
- return
- }
- // Create new node
- newNode := &LRUNode{
- key: key,
- value: value,
- }
- // If at max size, evict least recently used
- if len(c.cache) >= c.maxSize {
- c.evictLeastRecentlyUsed()
- }
- // Add to cache and move to head
- c.cache[key] = newNode
- c.addToHead(newNode)
- }
- // moveToHead moves a node to the head of the list (most recently used) - O(1)
- func (c *NormalizedValueCache) moveToHead(node *LRUNode) {
- c.removeNode(node)
- c.addToHead(node)
- }
- // addToHead adds a node right after the head - O(1)
- func (c *NormalizedValueCache) addToHead(node *LRUNode) {
- node.prev = c.head
- node.next = c.head.next
- c.head.next.prev = node
- c.head.next = node
- }
- // removeNode removes a node from the list - O(1)
- func (c *NormalizedValueCache) removeNode(node *LRUNode) {
- node.prev.next = node.next
- node.next.prev = node.prev
- }
- // removeTail removes the last node before tail (least recently used) - O(1)
- func (c *NormalizedValueCache) removeTail() *LRUNode {
- lastNode := c.tail.prev
- c.removeNode(lastNode)
- return lastNode
- }
- // evictLeastRecentlyUsed removes the least recently used item in O(1) time
- func (c *NormalizedValueCache) evictLeastRecentlyUsed() {
- tail := c.removeTail()
- delete(c.cache, tail.key)
- }
- // Clear clears all cached values
- func (c *NormalizedValueCache) Clear() {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.cache = make(map[string]*LRUNode)
- c.head.next = c.tail
- c.tail.prev = c.head
- }
- // GetStats returns cache statistics
- func (c *NormalizedValueCache) GetStats() (size int, maxSize int) {
- c.mu.RLock()
- defer c.mu.RUnlock()
- return len(c.cache), c.maxSize
- }
- // Global cache instance with size limit
- var normalizedValueCache = NewNormalizedValueCache(1000)
- // getCachedNormalizedValues returns cached normalized values or caches new ones
- func getCachedNormalizedValues(value interface{}) []string {
- // Create a string key for caching - more efficient than fmt.Sprintf
- typeStr := reflect.TypeOf(value).String()
- cacheKey := typeStr + ":" + fmt.Sprint(value)
- // Try to get from cache
- if cached, exists := normalizedValueCache.Get(cacheKey); exists {
- return cached
- }
- // Not in cache, normalize and store
- // Use the error-handling version for better error reporting
- normalized, err := normalizeToStringSliceWithError(value)
- if err != nil {
- glog.Warningf("Failed to normalize policy value %v: %v", value, err)
- // Fallback to string conversion for backward compatibility
- normalized = []string{fmt.Sprintf("%v", value)}
- }
- normalizedValueCache.Set(cacheKey, normalized)
- return normalized
- }
- // ConditionEvaluator evaluates policy conditions
- type ConditionEvaluator interface {
- Evaluate(conditionValue interface{}, contextValues []string) bool
- }
- // StringEqualsEvaluator evaluates StringEquals conditions
- type StringEqualsEvaluator struct{}
- func (e *StringEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- for _, contextValue := range contextValues {
- if expected == contextValue {
- return true
- }
- }
- }
- return false
- }
- // StringNotEqualsEvaluator evaluates StringNotEquals conditions
- type StringNotEqualsEvaluator struct{}
- func (e *StringNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- for _, contextValue := range contextValues {
- if expected == contextValue {
- return false
- }
- }
- }
- return true
- }
- // StringLikeEvaluator evaluates StringLike conditions (supports wildcards)
- type StringLikeEvaluator struct{}
- func (e *StringLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- patterns := getCachedNormalizedValues(conditionValue)
- for _, pattern := range patterns {
- for _, contextValue := range contextValues {
- if MatchesWildcard(pattern, contextValue) {
- return true
- }
- }
- }
- return false
- }
- // StringNotLikeEvaluator evaluates StringNotLike conditions
- type StringNotLikeEvaluator struct{}
- func (e *StringNotLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- patterns := getCachedNormalizedValues(conditionValue)
- for _, pattern := range patterns {
- for _, contextValue := range contextValues {
- if MatchesWildcard(pattern, contextValue) {
- return false
- }
- }
- }
- return true
- }
- // NumericEqualsEvaluator evaluates NumericEquals conditions
- type NumericEqualsEvaluator struct{}
- func (e *NumericEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if expectedFloat == contextFloat {
- return true
- }
- }
- }
- return false
- }
- // NumericNotEqualsEvaluator evaluates NumericNotEquals conditions
- type NumericNotEqualsEvaluator struct{}
- func (e *NumericNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if expectedFloat == contextFloat {
- return false
- }
- }
- }
- return true
- }
- // NumericLessThanEvaluator evaluates NumericLessThan conditions
- type NumericLessThanEvaluator struct{}
- func (e *NumericLessThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if contextFloat < expectedFloat {
- return true
- }
- }
- }
- return false
- }
- // NumericLessThanEqualsEvaluator evaluates NumericLessThanEquals conditions
- type NumericLessThanEqualsEvaluator struct{}
- func (e *NumericLessThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if contextFloat <= expectedFloat {
- return true
- }
- }
- }
- return false
- }
- // NumericGreaterThanEvaluator evaluates NumericGreaterThan conditions
- type NumericGreaterThanEvaluator struct{}
- func (e *NumericGreaterThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if contextFloat > expectedFloat {
- return true
- }
- }
- }
- return false
- }
- // NumericGreaterThanEqualsEvaluator evaluates NumericGreaterThanEquals conditions
- type NumericGreaterThanEqualsEvaluator struct{}
- func (e *NumericGreaterThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedFloat, err := strconv.ParseFloat(expected, 64)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextFloat, err := strconv.ParseFloat(contextValue, 64)
- if err != nil {
- continue
- }
- if contextFloat >= expectedFloat {
- return true
- }
- }
- }
- return false
- }
- // DateEqualsEvaluator evaluates DateEquals conditions
- type DateEqualsEvaluator struct{}
- func (e *DateEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if expectedTime.Equal(contextTime) {
- return true
- }
- }
- }
- return false
- }
- // DateNotEqualsEvaluator evaluates DateNotEquals conditions
- type DateNotEqualsEvaluator struct{}
- func (e *DateNotEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if expectedTime.Equal(contextTime) {
- return false
- }
- }
- }
- return true
- }
- // DateLessThanEvaluator evaluates DateLessThan conditions
- type DateLessThanEvaluator struct{}
- func (e *DateLessThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if contextTime.Before(expectedTime) {
- return true
- }
- }
- }
- return false
- }
- // DateLessThanEqualsEvaluator evaluates DateLessThanEquals conditions
- type DateLessThanEqualsEvaluator struct{}
- func (e *DateLessThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if contextTime.Before(expectedTime) || contextTime.Equal(expectedTime) {
- return true
- }
- }
- }
- return false
- }
- // DateGreaterThanEvaluator evaluates DateGreaterThan conditions
- type DateGreaterThanEvaluator struct{}
- func (e *DateGreaterThanEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if contextTime.After(expectedTime) {
- return true
- }
- }
- }
- return false
- }
- // DateGreaterThanEqualsEvaluator evaluates DateGreaterThanEquals conditions
- type DateGreaterThanEqualsEvaluator struct{}
- func (e *DateGreaterThanEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedTime, err := time.Parse(time.RFC3339, expected)
- if err != nil {
- continue
- }
- for _, contextValue := range contextValues {
- contextTime, err := time.Parse(time.RFC3339, contextValue)
- if err != nil {
- continue
- }
- if contextTime.After(expectedTime) || contextTime.Equal(expectedTime) {
- return true
- }
- }
- }
- return false
- }
- // BoolEvaluator evaluates Bool conditions
- type BoolEvaluator struct{}
- func (e *BoolEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- for _, contextValue := range contextValues {
- if strings.ToLower(expected) == strings.ToLower(contextValue) {
- return true
- }
- }
- }
- return false
- }
- // IpAddressEvaluator evaluates IpAddress conditions
- type IpAddressEvaluator struct{}
- func (e *IpAddressEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- _, expectedNet, err := net.ParseCIDR(expected)
- if err != nil {
- // Try parsing as single IP
- expectedIP := net.ParseIP(expected)
- if expectedIP == nil {
- glog.V(3).Infof("Failed to parse expected IP address: %s", expected)
- continue
- }
- for _, contextValue := range contextValues {
- contextIP := net.ParseIP(contextValue)
- if contextIP == nil {
- glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
- continue
- }
- if contextIP.Equal(expectedIP) {
- return true
- }
- }
- } else {
- // CIDR network
- for _, contextValue := range contextValues {
- contextIP := net.ParseIP(contextValue)
- if contextIP == nil {
- glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
- continue
- }
- if expectedNet.Contains(contextIP) {
- return true
- }
- }
- }
- }
- return false
- }
- // NotIpAddressEvaluator evaluates NotIpAddress conditions
- type NotIpAddressEvaluator struct{}
- func (e *NotIpAddressEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- _, expectedNet, err := net.ParseCIDR(expected)
- if err != nil {
- // Try parsing as single IP
- expectedIP := net.ParseIP(expected)
- if expectedIP == nil {
- glog.V(3).Infof("Failed to parse expected IP address: %s", expected)
- continue
- }
- for _, contextValue := range contextValues {
- contextIP := net.ParseIP(contextValue)
- if contextIP == nil {
- glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
- continue
- }
- if contextIP.Equal(expectedIP) {
- return false
- }
- }
- } else {
- // CIDR network
- for _, contextValue := range contextValues {
- contextIP := net.ParseIP(contextValue)
- if contextIP == nil {
- glog.V(3).Infof("Failed to parse IP address: %s", contextValue)
- continue
- }
- if expectedNet.Contains(contextIP) {
- return false
- }
- }
- }
- }
- return true
- }
- // ArnEqualsEvaluator evaluates ArnEquals conditions
- type ArnEqualsEvaluator struct{}
- func (e *ArnEqualsEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- for _, contextValue := range contextValues {
- if expected == contextValue {
- return true
- }
- }
- }
- return false
- }
- // ArnLikeEvaluator evaluates ArnLike conditions
- type ArnLikeEvaluator struct{}
- func (e *ArnLikeEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- patterns := getCachedNormalizedValues(conditionValue)
- for _, pattern := range patterns {
- for _, contextValue := range contextValues {
- if MatchesWildcard(pattern, contextValue) {
- return true
- }
- }
- }
- return false
- }
- // NullEvaluator evaluates Null conditions
- type NullEvaluator struct{}
- func (e *NullEvaluator) Evaluate(conditionValue interface{}, contextValues []string) bool {
- expectedValues := getCachedNormalizedValues(conditionValue)
- for _, expected := range expectedValues {
- expectedBool := strings.ToLower(expected) == "true"
- contextExists := len(contextValues) > 0
- if expectedBool && !contextExists {
- return true // Key should be null and it is
- }
- if !expectedBool && contextExists {
- return true // Key should not be null and it isn't
- }
- }
- return false
- }
- // GetConditionEvaluator returns the appropriate evaluator for a condition operator
- func GetConditionEvaluator(operator string) (ConditionEvaluator, error) {
- switch operator {
- case "StringEquals":
- return &StringEqualsEvaluator{}, nil
- case "StringNotEquals":
- return &StringNotEqualsEvaluator{}, nil
- case "StringLike":
- return &StringLikeEvaluator{}, nil
- case "StringNotLike":
- return &StringNotLikeEvaluator{}, nil
- case "NumericEquals":
- return &NumericEqualsEvaluator{}, nil
- case "NumericNotEquals":
- return &NumericNotEqualsEvaluator{}, nil
- case "NumericLessThan":
- return &NumericLessThanEvaluator{}, nil
- case "NumericLessThanEquals":
- return &NumericLessThanEqualsEvaluator{}, nil
- case "NumericGreaterThan":
- return &NumericGreaterThanEvaluator{}, nil
- case "NumericGreaterThanEquals":
- return &NumericGreaterThanEqualsEvaluator{}, nil
- case "DateEquals":
- return &DateEqualsEvaluator{}, nil
- case "DateNotEquals":
- return &DateNotEqualsEvaluator{}, nil
- case "DateLessThan":
- return &DateLessThanEvaluator{}, nil
- case "DateLessThanEquals":
- return &DateLessThanEqualsEvaluator{}, nil
- case "DateGreaterThan":
- return &DateGreaterThanEvaluator{}, nil
- case "DateGreaterThanEquals":
- return &DateGreaterThanEqualsEvaluator{}, nil
- case "Bool":
- return &BoolEvaluator{}, nil
- case "IpAddress":
- return &IpAddressEvaluator{}, nil
- case "NotIpAddress":
- return &NotIpAddressEvaluator{}, nil
- case "ArnEquals":
- return &ArnEqualsEvaluator{}, nil
- case "ArnLike":
- return &ArnLikeEvaluator{}, nil
- case "Null":
- return &NullEvaluator{}, nil
- default:
- return nil, fmt.Errorf("unsupported condition operator: %s", operator)
- }
- }
- // EvaluateConditions evaluates all conditions in a policy statement
- func EvaluateConditions(conditions PolicyConditions, contextValues map[string][]string) bool {
- if len(conditions) == 0 {
- return true // No conditions means always true
- }
- for operator, conditionMap := range conditions {
- conditionEvaluator, err := GetConditionEvaluator(operator)
- if err != nil {
- glog.Warningf("Unsupported condition operator: %s", operator)
- continue
- }
- for key, value := range conditionMap {
- contextVals, exists := contextValues[key]
- if !exists {
- contextVals = []string{}
- }
- if !conditionEvaluator.Evaluate(value.Strings(), contextVals) {
- return false // If any condition fails, the whole condition block fails
- }
- }
- }
- return true
- }
- // EvaluateConditionsLegacy evaluates conditions using the old interface{} format for backward compatibility
- func EvaluateConditionsLegacy(conditions map[string]interface{}, contextValues map[string][]string) bool {
- if len(conditions) == 0 {
- return true // No conditions means always true
- }
- for operator, conditionMap := range conditions {
- conditionEvaluator, err := GetConditionEvaluator(operator)
- if err != nil {
- glog.Warningf("Unsupported condition operator: %s", operator)
- continue
- }
- conditionMapTyped, ok := conditionMap.(map[string]interface{})
- if !ok {
- glog.Warningf("Invalid condition format for operator: %s", operator)
- continue
- }
- for key, value := range conditionMapTyped {
- contextVals, exists := contextValues[key]
- if !exists {
- contextVals = []string{}
- }
- if !conditionEvaluator.Evaluate(value, contextVals) {
- return false // If any condition fails, the whole condition block fails
- }
- }
- }
- return true
- }
|