github.com/kiali/kiali@v1.84.0/business/checkers/authorization/namespace_method_checker.go (about)

     1  package authorization
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  
     8  	api_security_v1beta "istio.io/api/security/v1beta1"
     9  	security_v1beta "istio.io/client-go/pkg/apis/security/v1beta1"
    10  
    11  	"github.com/kiali/kiali/models"
    12  	"github.com/kiali/kiali/util/httputil"
    13  )
    14  
    15  var methodMatcher = regexp.MustCompile(`^((\/[a-zA-Z\.]+)+)(\/[a-zA-Z]+)$`)
    16  
    17  type NamespaceMethodChecker struct {
    18  	AuthorizationPolicy *security_v1beta.AuthorizationPolicy
    19  	Namespaces          models.NamespaceNames
    20  }
    21  
    22  func (ap NamespaceMethodChecker) Check() ([]*models.IstioCheck, bool) {
    23  	checks, valid := make([]*models.IstioCheck, 0), true
    24  
    25  	for ruleIdx, rule := range ap.AuthorizationPolicy.Spec.Rules {
    26  		if rule == nil {
    27  			continue
    28  		}
    29  		if len(rule.From) > 0 {
    30  			toChecks, toValid := ap.validateFromField(ruleIdx, rule.From)
    31  			checks = append(checks, toChecks...)
    32  			valid = valid && toValid
    33  		}
    34  		if len(rule.To) > 0 {
    35  			fromChecks, fromValid := ap.validateToField(ruleIdx, rule.To)
    36  			checks = append(checks, fromChecks...)
    37  			valid = valid && fromValid
    38  		}
    39  	}
    40  	return checks, valid
    41  }
    42  
    43  func (ap NamespaceMethodChecker) validateFromField(ruleIdx int, from []*api_security_v1beta.Rule_From) ([]*models.IstioCheck, bool) {
    44  	if len(from) == 0 {
    45  		return nil, true
    46  	}
    47  
    48  	checks, valid := make([]*models.IstioCheck, 0, len(from)), true
    49  	for fromIdx, f := range from {
    50  		if f == nil {
    51  			continue
    52  		}
    53  
    54  		if f.Source == nil {
    55  			continue
    56  		}
    57  
    58  		if len(f.Source.Namespaces) == 0 {
    59  			continue
    60  		}
    61  
    62  		for i, n := range f.Source.Namespaces {
    63  			if !ap.Namespaces.Includes(n) {
    64  				valid = true
    65  				path := fmt.Sprintf("spec/rules[%d]/from[%d]/source/namespaces[%d]", ruleIdx, fromIdx, i)
    66  				validation := models.Build("authorizationpolicy.source.namespacenotfound", path)
    67  				checks = append(checks, &validation)
    68  			}
    69  		}
    70  	}
    71  
    72  	return checks, valid
    73  }
    74  
    75  func (ap NamespaceMethodChecker) validateToField(ruleIdx int, to []*api_security_v1beta.Rule_To) ([]*models.IstioCheck, bool) {
    76  	if len(to) == 0 {
    77  		return nil, true
    78  	}
    79  
    80  	checks, valid := make([]*models.IstioCheck, 0, len(to)), true
    81  	for toIdx, t := range to {
    82  		if t == nil {
    83  			continue
    84  		}
    85  
    86  		if t.Operation == nil {
    87  			continue
    88  		}
    89  
    90  		if len(t.Operation.Methods) == 0 {
    91  			continue
    92  		}
    93  
    94  		for i, m := range t.Operation.Methods {
    95  			if !validMethod(m) {
    96  				valid = true
    97  				path := fmt.Sprintf("spec/rules[%d]/to[%d]/operation/methods[%d]", ruleIdx, toIdx, i)
    98  				validation := models.Build("authorizationpolicy.to.wrongmethod", path)
    99  				checks = append(checks, &validation)
   100  			}
   101  		}
   102  	}
   103  
   104  	return checks, valid
   105  }
   106  
   107  func validMethod(m string) bool {
   108  	valid := false
   109  
   110  	for _, httpMethod := range httputil.HttpMethods() {
   111  		// HTTP methods allowed or
   112  		// For gRPC service, a fully-qualified name like “/package.service/method”
   113  		valid = valid || (strings.TrimSpace(strings.ToUpper(m)) == httpMethod || methodMatcher.MatchString(m))
   114  	}
   115  
   116  	return valid
   117  }