...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/rules/banner_rules.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/rules

     1  package rulesengine
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  )
     7  
     8  func (reng RulesEngine) ReadRulesForBanner(ctx context.Context, bannerName string) ([]Rule, error) {
     9  	ruleSegments, err := reng.ds.ReadRulesForBanner(ctx, bannerName)
    10  	if err != nil {
    11  		return []Rule{}, fmt.Errorf("error when calling ReadRulesForBanner: %s", err)
    12  	}
    13  	return assembleRules(ruleSegments), nil
    14  }
    15  
    16  func (reng RulesEngine) ReadRulesForAllBanners(ctx context.Context) ([]ReadBannerRule, error) {
    17  	bannerRules, err := reng.ds.ReadRulesForAllBanners(ctx)
    18  	if err != nil {
    19  		return nil, err
    20  	}
    21  
    22  	return assembleGetBannerRule(bannerRules)
    23  }
    24  
    25  func assembleGetBannerRule(bannerSegments []RuleSegment) ([]ReadBannerRule, error) {
    26  	var res []ReadBannerRule
    27  	for _, segment := range bannerSegments {
    28  		// since assembleRules and assembleGetBannerRules operate on the same data, we need to check
    29  		// here if the banners are all defined and fail fast if not.
    30  		if segment.Banner.BannerID == "" || segment.Banner.BannerName == "" {
    31  			return res, fmt.Errorf("error in assembeGetBannerRule: Banner was nil")
    32  		}
    33  		res = appendBannerSegment(res, segment)
    34  	}
    35  
    36  	return res, nil
    37  }
    38  
    39  func appendBannerSegment(rules []ReadBannerRule, segment RuleSegment) []ReadBannerRule {
    40  	for idx, rule := range rules {
    41  		if rule.Command.ID != segment.Command.ID {
    42  			continue
    43  		}
    44  
    45  		rules[idx].Banners = appendPrivToBannerOverlay(rule.Banners, segment.Banner, segment.Privilege)
    46  
    47  		return rules
    48  	}
    49  
    50  	rules = append(rules, ReadBannerRule{
    51  		Command: segment.Command,
    52  		Banners: []BannerPrivOverrides{{
    53  			Banner: segment.Banner,
    54  			Privileges: []Privilege{
    55  				segment.Privilege,
    56  			},
    57  		}},
    58  	})
    59  
    60  	return rules
    61  }
    62  
    63  func appendPrivToBannerOverlay(overrides []BannerPrivOverrides, banner Banner, privilege Privilege) []BannerPrivOverrides {
    64  	for idx, override := range overrides {
    65  		if override.Banner.BannerID == banner.BannerID {
    66  			overrides[idx].Privileges = append(override.Privileges, privilege)
    67  			return overrides
    68  		}
    69  	}
    70  
    71  	overrides = append(overrides, BannerPrivOverrides{
    72  		Banner:     banner,
    73  		Privileges: []Privilege{privilege},
    74  	})
    75  	return overrides
    76  }
    77  
    78  func (reng RulesEngine) DeletePrivilegeFromBannerRule(ctx context.Context, bannerName, commandName, privilegeName string) (DeleteResult, error) {
    79  	return reng.ds.DeletePrivilegeFromBannerRule(ctx, bannerName, commandName, privilegeName)
    80  }
    81  
    82  // ReadAllRulesForCommand reads all rules associated to a command (Default & Banner specific overrides).
    83  // Empty fields will always return the datatype specified and not nil.
    84  func (reng RulesEngine) ReadAllRulesForCommand(ctx context.Context, commandName string) (RuleWithOverrides, error) {
    85  	// read rule for commandName.
    86  	ruleSegment, err := reng.ds.ReadDefaultRulesForCommand(ctx, commandName)
    87  	if err != nil {
    88  		return RuleWithOverrides{}, fmt.Errorf("error finding default rules: %s", err)
    89  	}
    90  	defaultRules := assembleRules(ruleSegment)
    91  	// If defaultRules is empty this could mean one of two things:
    92  	// 1. the command does not exist and its ok to return early
    93  	// 2. the command exists but there are no default rules associated to that command
    94  	// 		a) There may or may not be banner specific overrides
    95  	// 		b) If there are banner specific overrides we need to be able set the commandID without panicking
    96  	res := RuleWithOverrides{}
    97  	if len(defaultRules) != 0 {
    98  		// update resulting command from query
    99  		res.Command = defaultRules[0].Command
   100  		res.Default.Privileges = defaultRules[0].Privileges
   101  	}
   102  
   103  	allBannerRules, err := reng.ReadBannerRulesForCommand(ctx, commandName)
   104  	if err != nil {
   105  		return res, fmt.Errorf("error finding banner rules: %s", err)
   106  	}
   107  	for _, banner := range allBannerRules.Banners {
   108  		for _, priv := range banner.Privileges {
   109  			res.Banners = appendPrivToBannerOverlay(res.Banners, banner.Banner, priv)
   110  		}
   111  		res.Command = allBannerRules.Command
   112  	}
   113  
   114  	if len(res.Banners) == 0 {
   115  		// make sure the return type is defined
   116  		res.Banners = []BannerPrivOverrides{}
   117  	}
   118  	if len(res.Banners) == 0 && len(res.Default.Privileges) == 0 {
   119  		return RuleWithOverrides{}, nil
   120  	}
   121  	return res, nil
   122  }
   123  
   124  func (reng RulesEngine) AddBannerRules(ctx context.Context, bannerName string, rules WriteRules) (AddRuleResult, error) {
   125  	parts := splitPostRulesToBannerSegment(bannerName, rules)
   126  	return reng.ds.AddBannerRules(ctx, parts)
   127  }
   128  
   129  func splitPostRulesToBannerSegment(bannerName string, rules []WriteRule) []RuleSegment {
   130  	var parts []RuleSegment
   131  
   132  	banner := Banner{BannerName: bannerName}
   133  
   134  	for _, rule := range rules {
   135  		command := Command{Name: rule.Command}
   136  		for _, privilege := range rule.Privileges {
   137  			privilege := Privilege{Name: privilege}
   138  
   139  			parts = append(parts, RuleSegment{
   140  				Banner:    banner,
   141  				Command:   command,
   142  				Privilege: privilege,
   143  			})
   144  		}
   145  	}
   146  
   147  	return parts
   148  }
   149  
   150  func (reng RulesEngine) ReadBannerRulesForCommand(ctx context.Context, commandName string) (ReadBannerRule, error) {
   151  	parts, err := reng.ds.ReadBannerRulesForCommand(ctx, commandName)
   152  	if err != nil {
   153  		return ReadBannerRule{}, fmt.Errorf("error querying for rules: %w", err)
   154  	}
   155  
   156  	if len(parts) == 0 {
   157  		return ReadBannerRule{}, nil
   158  	}
   159  
   160  	rules, err := assembleGetBannerRule(parts)
   161  	if err != nil {
   162  		return ReadBannerRule{}, err
   163  	}
   164  
   165  	if len(rules) != 1 {
   166  		return ReadBannerRule{}, fmt.Errorf("storage returned unexpected number of rules")
   167  	}
   168  
   169  	return rules[0], nil
   170  }
   171  
   172  func (reng RulesEngine) ReadBannerRulesForCommandAndBanner(ctx context.Context, bannerName string, commandName string) (Rule, error) {
   173  	parts, err := reng.ds.ReadBannerRulesForCommandAndBanner(ctx, bannerName, commandName)
   174  	if err != nil {
   175  		return Rule{}, fmt.Errorf("error querying for rules: %w", err)
   176  	}
   177  
   178  	if len(parts) == 0 {
   179  		return Rule{}, nil
   180  	}
   181  
   182  	rules := assembleRules(parts)
   183  
   184  	if len(rules) != 1 {
   185  		return Rule{}, fmt.Errorf("storage returned unexpected number of rules")
   186  	}
   187  
   188  	return rules[0], nil
   189  }
   190  

View as plain text