pkg/authority/rule/authorization/rule.go (213 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package authorization import ( "encoding/json" "net/netip" "strings" "github.com/apache/dubbo-admin/pkg/logger" "github.com/tidwall/gjson" "github.com/apache/dubbo-admin/pkg/authority/rule" ) const RuleType = "authorization/v1beta1" type ToClient struct { revision int64 data string } func (r *ToClient) Type() string { return RuleType } func (r *ToClient) Revision() int64 { return r.revision } func (r *ToClient) Data() string { return r.data } type Origin struct { revision int64 data map[string]*Policy } func (o *Origin) Type() string { return RuleType } func (o *Origin) Revision() int64 { return o.revision } func (o *Origin) Exact(endpoint *rule.Endpoint) (rule.ToClient, error) { matchedRule := make([]*PolicyToClient, 0, len(o.data)) for _, v := range o.data { if v.Spec == nil { continue } if v.Spec.Rules != nil { match := true for _, policyRule := range v.Spec.Rules { if !matchSelector(policyRule.To, endpoint) { match = false break } } if !match { continue } } toClient := v.CopyToClient() matchedRule = append(matchedRule, toClient) } allRule, err := json.Marshal(matchedRule) if err != nil { return nil, err } return &ToClient{ revision: o.revision, data: string(allRule), }, nil } func matchSelector(target *Target, endpoint *rule.Endpoint) bool { if endpoint == nil { return true } if !matchNamespace(target, endpoint) { return false } if !matchNotNamespace(target, endpoint) { return false } if !matchIPBlocks(target, endpoint) { return false } if !matchNotIPBlocks(target, endpoint) { return false } if !matchPrincipals(target, endpoint) { return false } if !matchNotPrincipals(target, endpoint) { return false } endpointJSON, err := json.Marshal(endpoint) if err != nil { logger.Sugar().Warnf("marshal endpoint failed, %v", err) return false } if !matchExtends(target, endpointJSON) { return false } return matchNotExtends(target, endpointJSON) } func matchNotExtends(target *Target, endpointJSON []byte) bool { if len(target.NotExtends) == 0 { return true } for _, extend := range target.NotExtends { if gjson.Get(string(endpointJSON), extend.Key).String() == extend.Value { return false } } return true } func matchExtends(target *Target, endpointJSON []byte) bool { if len(target.Extends) == 0 { return true } for _, extend := range target.Extends { if gjson.Get(string(endpointJSON), extend.Key).String() == extend.Value { return true } } return false } func matchNotPrincipals(target *Target, endpoint *rule.Endpoint) bool { if len(target.NotPrincipals) == 0 { return true } for _, principal := range target.NotPrincipals { if principal == endpoint.SpiffeID { return false } if strings.ReplaceAll(endpoint.SpiffeID, "spiffe://", "") == principal { return false } } return true } func matchPrincipals(target *Target, endpoint *rule.Endpoint) bool { if len(target.Principals) == 0 { return true } for _, principal := range target.Principals { if principal == endpoint.SpiffeID { return true } if strings.ReplaceAll(endpoint.SpiffeID, "spiffe://", "") == principal { return true } } return false } func matchNotIPBlocks(target *Target, endpoint *rule.Endpoint) bool { if len(target.NotIpBlocks) == 0 { return true } for _, ipBlock := range target.NotIpBlocks { prefix, err := netip.ParsePrefix(ipBlock) if err != nil { logger.Sugar().Warnf("parse ip block %s failed, %v", ipBlock, err) continue } for _, ip := range endpoint.Ips { addr, err := netip.ParseAddr(ip) if err != nil { logger.Sugar().Warnf("parse ip %s failed, %v", ip, err) continue } if prefix.Contains(addr) { return false } } } return true } func matchIPBlocks(target *Target, endpoint *rule.Endpoint) bool { if len(target.IpBlocks) == 0 { return true } for _, ipBlock := range target.IpBlocks { prefix, err := netip.ParsePrefix(ipBlock) if err != nil { logger.Sugar().Warnf("parse ip block %s failed, %v", ipBlock, err) continue } for _, ip := range endpoint.Ips { addr, err := netip.ParseAddr(ip) if err != nil { logger.Sugar().Warnf("parse ip %s failed, %v", ip, err) continue } if prefix.Contains(addr) { return true } } } return false } func matchNotNamespace(target *Target, endpoint *rule.Endpoint) bool { if len(target.NotNamespaces) == 0 { return true } for _, namespace := range target.NotNamespaces { if endpoint.KubernetesEnv != nil && namespace == endpoint.KubernetesEnv.Namespace { return false } } return true } func matchNamespace(target *Target, endpoint *rule.Endpoint) bool { if len(target.Namespaces) == 0 { return true } for _, namespace := range target.Namespaces { if endpoint.KubernetesEnv != nil && namespace == endpoint.KubernetesEnv.Namespace { return true } } return false }