github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/appprotect/app_protect_configuration.go (about)

     1  package appprotect
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"time"
     7  
     8  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
     9  	"k8s.io/apimachinery/pkg/runtime/schema"
    10  )
    11  
    12  const timeLayout = time.RFC3339
    13  
    14  // reasons for invalidity
    15  const (
    16  	failedValidationErrorMsg = "Validation Failed"
    17  	missingUserSigErrorMsg   = "Policy has unsatisfied signature requirements"
    18  	duplicatedTagsErrorMsg   = "Duplicate tag set"
    19  	invalidTimestampErrorMsg = "Invalid timestamp"
    20  )
    21  
    22  var (
    23  	// PolicyGVR is the group version resource of the appprotect policy
    24  	PolicyGVR = schema.GroupVersionResource{
    25  		Group:    "appprotect.f5.com",
    26  		Version:  "v1beta1",
    27  		Resource: "appolicies",
    28  	}
    29  	// PolicyGVK is the group version kind of the appprotect policy
    30  	PolicyGVK = schema.GroupVersionKind{
    31  		Group:   "appprotect.f5.com",
    32  		Version: "v1beta1",
    33  		Kind:    "APPolicy",
    34  	}
    35  
    36  	// LogConfGVR is the group version resource of the appprotect policy
    37  	LogConfGVR = schema.GroupVersionResource{
    38  		Group:    "appprotect.f5.com",
    39  		Version:  "v1beta1",
    40  		Resource: "aplogconfs",
    41  	}
    42  	// LogConfGVK is the group version kind of the appprotect policy
    43  	LogConfGVK = schema.GroupVersionKind{
    44  		Group:   "appprotect.f5.com",
    45  		Version: "v1beta1",
    46  		Kind:    "APLogConf",
    47  	}
    48  
    49  	// UserSigGVR is the group version resource of the appprotect policy
    50  	UserSigGVR = schema.GroupVersionResource{
    51  		Group:    "appprotect.f5.com",
    52  		Version:  "v1beta1",
    53  		Resource: "apusersigs",
    54  	}
    55  	// UserSigGVK is the group version kind of the appprotect policy
    56  	UserSigGVK = schema.GroupVersionKind{
    57  		Group:   "appprotect.f5.com",
    58  		Version: "v1beta1",
    59  		Kind:    "APUserSig",
    60  	}
    61  )
    62  
    63  // UserSigChange holds resources that are affected by changes in UserSigs
    64  type UserSigChange struct {
    65  	PolicyDeletions     []*unstructured.Unstructured
    66  	PolicyAddsOrUpdates []*unstructured.Unstructured
    67  	UserSigs            []*unstructured.Unstructured
    68  }
    69  
    70  // Operation defines an operation to perform for an App Protect resource.
    71  type Operation int
    72  
    73  const (
    74  	// Delete the config of the resource
    75  	Delete Operation = iota
    76  	// AddOrUpdate the config of the resource
    77  	AddOrUpdate
    78  )
    79  
    80  // Change represents a change in an App Protect resource
    81  type Change struct {
    82  	// Op is an operation that needs be performed on the resource.
    83  	Op Operation
    84  	// Resource is the target resource.
    85  	Resource interface{}
    86  }
    87  
    88  // Problem represents a problem with an App Protect resource
    89  type Problem struct {
    90  	// Object is a configuration object.
    91  	Object *unstructured.Unstructured
    92  	// Reason tells the reason. It matches the reason in the events of our configuration objects.
    93  	Reason string
    94  	// Message gives the details about the problem. It matches the message in the events of our configuration objects.
    95  	Message string
    96  }
    97  
    98  // Configuration configures App Protect resources that the Ingress Controller uses.
    99  type Configuration interface {
   100  	AddOrUpdatePolicy(policyObj *unstructured.Unstructured) (changes []Change, problems []Problem)
   101  	AddOrUpdateLogConf(logConfObj *unstructured.Unstructured) (changes []Change, problems []Problem)
   102  	AddOrUpdateUserSig(userSigObj *unstructured.Unstructured) (change UserSigChange, problems []Problem)
   103  	GetAppResource(kind, key string) (*unstructured.Unstructured, error)
   104  	DeletePolicy(key string) (changes []Change, problems []Problem)
   105  	DeleteLogConf(key string) (changes []Change, problems []Problem)
   106  	DeleteUserSig(key string) (change UserSigChange, problems []Problem)
   107  }
   108  
   109  // ConfigurationImpl holds representations of App Protect cluster resources
   110  type ConfigurationImpl struct {
   111  	Policies map[string]*PolicyEx
   112  	LogConfs map[string]*LogConfEx
   113  	UserSigs map[string]*UserSigEx
   114  }
   115  
   116  // NewConfiguration creates a new App Protect Configuration
   117  func NewConfiguration() Configuration {
   118  	return newConfigurationImpl()
   119  }
   120  
   121  // NewConfiguration creates a new App Protect Configuration
   122  func newConfigurationImpl() *ConfigurationImpl {
   123  	return &ConfigurationImpl{
   124  		Policies: make(map[string]*PolicyEx),
   125  		LogConfs: make(map[string]*LogConfEx),
   126  		UserSigs: make(map[string]*UserSigEx),
   127  	}
   128  }
   129  
   130  // PolicyEx represents an App Protect policy cluster resource
   131  type PolicyEx struct {
   132  	Obj           *unstructured.Unstructured
   133  	SignatureReqs []SignatureReq
   134  	IsValid       bool
   135  	ErrorMsg      string
   136  }
   137  
   138  func (pol *PolicyEx) setInvalid(reason string) {
   139  	pol.IsValid = false
   140  	pol.ErrorMsg = reason
   141  }
   142  
   143  func (pol *PolicyEx) setValid() {
   144  	pol.IsValid = true
   145  	pol.ErrorMsg = ""
   146  }
   147  
   148  // SignatureReq describes a signature that is required by the policy
   149  type SignatureReq struct {
   150  	Tag      string
   151  	RevTimes *RevTimes
   152  }
   153  
   154  // RevTimes are requirements for signature revision time
   155  type RevTimes struct {
   156  	MinRevTime *time.Time
   157  	MaxRevTime *time.Time
   158  }
   159  
   160  // LogConfEx represents an App Protect Log Configuration cluster resource
   161  type LogConfEx struct {
   162  	Obj      *unstructured.Unstructured
   163  	IsValid  bool
   164  	ErrorMsg string
   165  }
   166  
   167  // UserSigEx represents an App Protect User Defined Signature cluster resource
   168  type UserSigEx struct {
   169  	Obj      *unstructured.Unstructured
   170  	Tag      string
   171  	RevTime  *time.Time
   172  	IsValid  bool
   173  	ErrorMsg string
   174  }
   175  
   176  func (sig *UserSigEx) setInvalid(reason string) {
   177  	sig.IsValid = false
   178  	sig.ErrorMsg = reason
   179  }
   180  
   181  func (sig *UserSigEx) setValid() {
   182  	sig.IsValid = true
   183  	sig.ErrorMsg = ""
   184  }
   185  
   186  type appProtectUserSigSlice []*UserSigEx
   187  
   188  func (s appProtectUserSigSlice) Len() int {
   189  	return len(s)
   190  }
   191  
   192  func (s appProtectUserSigSlice) Less(i, j int) bool {
   193  	if s[i].Obj.GetCreationTimestamp().Time.Equal(s[j].Obj.GetCreationTimestamp().Time) {
   194  		return s[i].Obj.GetUID() > s[j].Obj.GetUID()
   195  	}
   196  	return s[i].Obj.GetCreationTimestamp().Time.Before(s[j].Obj.GetCreationTimestamp().Time)
   197  }
   198  
   199  func (s appProtectUserSigSlice) Swap(i, j int) {
   200  	s[i], s[j] = s[j], s[i]
   201  }
   202  
   203  func createAppProtectPolicyEx(policyObj *unstructured.Unstructured) (*PolicyEx, error) {
   204  	err := validateAppProtectPolicy(policyObj)
   205  	if err != nil {
   206  		errMsg := fmt.Sprintf("Error validating policy %s: %v", policyObj.GetName(), err)
   207  		return &PolicyEx{Obj: policyObj, IsValid: false, ErrorMsg: failedValidationErrorMsg}, fmt.Errorf(errMsg)
   208  	}
   209  	sigReqs := []SignatureReq{}
   210  	// Check if policy has signature requirement (revision timestamp) and map them to tags
   211  	list, found, err := unstructured.NestedSlice(policyObj.Object, "spec", "policy", "signature-requirements")
   212  	if err != nil {
   213  		errMsg := fmt.Sprintf("Error retrieving Signature requirements from %s: %v", policyObj.GetName(), err)
   214  		return &PolicyEx{Obj: policyObj, IsValid: false, ErrorMsg: failedValidationErrorMsg}, fmt.Errorf(errMsg)
   215  	}
   216  	if found {
   217  		for _, req := range list {
   218  			requirement := req.(map[string]interface{})
   219  			if reqTag, ok := requirement["tag"]; ok {
   220  				timeReq, err := buildRevTimes(requirement)
   221  				if err != nil {
   222  					errMsg := fmt.Sprintf("Error creating time requirements from %s: %v", policyObj.GetName(), err)
   223  					return &PolicyEx{Obj: policyObj, IsValid: false, ErrorMsg: invalidTimestampErrorMsg}, fmt.Errorf(errMsg)
   224  				}
   225  				sigReqs = append(sigReqs, SignatureReq{Tag: reqTag.(string), RevTimes: &timeReq})
   226  			}
   227  		}
   228  	}
   229  	return &PolicyEx{
   230  		Obj:           policyObj,
   231  		SignatureReqs: sigReqs,
   232  		IsValid:       true,
   233  	}, nil
   234  }
   235  
   236  func buildRevTimes(requirement map[string]interface{}) (RevTimes, error) {
   237  	timeReq := RevTimes{}
   238  	if minRev, ok := requirement["minRevisionDatetime"]; ok {
   239  		minRevTime, err := time.Parse(timeLayout, minRev.(string))
   240  		if err != nil {
   241  			errMsg := fmt.Sprintf("Error Parsing time from minRevisionDatetime %v", err)
   242  			return timeReq, fmt.Errorf(errMsg)
   243  		}
   244  		timeReq.MinRevTime = &minRevTime
   245  	}
   246  	if maxRev, ok := requirement["maxRevisionDatetime"]; ok {
   247  		maxRevTime, err := time.Parse(timeLayout, maxRev.(string))
   248  		if err != nil {
   249  			errMsg := fmt.Sprintf("Error Parsing time from maxRevisionDatetime  %v", err)
   250  			return timeReq, fmt.Errorf(errMsg)
   251  		}
   252  		timeReq.MaxRevTime = &maxRevTime
   253  	}
   254  	return timeReq, nil
   255  }
   256  
   257  func createAppProtectLogConfEx(logConfObj *unstructured.Unstructured) (*LogConfEx, error) {
   258  	err := validateAppProtectLogConf(logConfObj)
   259  	if err != nil {
   260  		return &LogConfEx{
   261  			Obj:      logConfObj,
   262  			IsValid:  false,
   263  			ErrorMsg: failedValidationErrorMsg,
   264  		}, err
   265  	}
   266  	return &LogConfEx{
   267  		Obj:     logConfObj,
   268  		IsValid: true,
   269  	}, nil
   270  }
   271  
   272  func createAppProtectUserSigEx(userSigObj *unstructured.Unstructured) (*UserSigEx, error) {
   273  	sTag := ""
   274  	err := validateAppProtectUserSig(userSigObj)
   275  	if err != nil {
   276  		errMsg := failedValidationErrorMsg
   277  		return &UserSigEx{Obj: userSigObj, IsValid: false, Tag: sTag, ErrorMsg: errMsg}, fmt.Errorf(errMsg)
   278  	}
   279  	// Previous validation ensures there will be no errors
   280  	tag, found, _ := unstructured.NestedString(userSigObj.Object, "spec", "tag")
   281  	if found {
   282  		sTag = tag
   283  	}
   284  	revTimeString, revTimeFound, _ := unstructured.NestedString(userSigObj.Object, "spec", "revisionDatetime")
   285  	if revTimeFound {
   286  		revTime, err := time.Parse(timeLayout, revTimeString)
   287  		if err != nil {
   288  			errMsg := invalidTimestampErrorMsg
   289  			return &UserSigEx{Obj: userSigObj, IsValid: false, ErrorMsg: errMsg}, fmt.Errorf(errMsg)
   290  		}
   291  		return &UserSigEx{Obj: userSigObj,
   292  			Tag:     sTag,
   293  			RevTime: &revTime,
   294  			IsValid: true}, nil
   295  	}
   296  	return &UserSigEx{
   297  		Obj:     userSigObj,
   298  		Tag:     sTag,
   299  		IsValid: true}, nil
   300  }
   301  
   302  func isReqSatisfiedByUserSig(sigReq SignatureReq, sig *UserSigEx) bool {
   303  	if sig.Tag == "" || sig.Tag != sigReq.Tag {
   304  		return false
   305  	}
   306  	if sigReq.RevTimes == nil || sig.RevTime == nil {
   307  		return sig.Tag == sigReq.Tag
   308  	}
   309  	if sigReq.RevTimes.MinRevTime != nil && sigReq.RevTimes.MaxRevTime != nil {
   310  		return sig.RevTime.Before(*sigReq.RevTimes.MaxRevTime) && sig.RevTime.After(*sigReq.RevTimes.MinRevTime)
   311  	}
   312  	if sigReq.RevTimes.MaxRevTime != nil && sig.RevTime.Before(*sigReq.RevTimes.MaxRevTime) {
   313  		return true
   314  	}
   315  	if sigReq.RevTimes.MinRevTime != nil && sig.RevTime.After(*sigReq.RevTimes.MinRevTime) {
   316  		return true
   317  	}
   318  	return false
   319  }
   320  
   321  func isReqSatisfiedByUserSigs(sigReq SignatureReq, sigs map[string]*UserSigEx) bool {
   322  	for _, sig := range sigs {
   323  		if isReqSatisfiedByUserSig(sigReq, sig) && sig.IsValid {
   324  			return true
   325  		}
   326  	}
   327  	return false
   328  }
   329  
   330  func (ci *ConfigurationImpl) verifyPolicyAgainstUserSigs(policy *PolicyEx) bool {
   331  	for _, sigreq := range policy.SignatureReqs {
   332  		if !isReqSatisfiedByUserSigs(sigreq, ci.UserSigs) {
   333  			return false
   334  		}
   335  	}
   336  	return true
   337  }
   338  
   339  // AddOrUpdatePolicy adds or updates an App Protect Policy to App Protect Configuration
   340  func (ci *ConfigurationImpl) AddOrUpdatePolicy(policyObj *unstructured.Unstructured) (changes []Change, problems []Problem) {
   341  	resNsName := GetNsName(policyObj)
   342  	policy, err := createAppProtectPolicyEx(policyObj)
   343  	if err != nil {
   344  		ci.Policies[resNsName] = policy
   345  		return append(changes, Change{Op: Delete, Resource: policy}),
   346  			append(problems, Problem{Object: policyObj, Reason: "Rejected", Message: err.Error()})
   347  	}
   348  	if ci.verifyPolicyAgainstUserSigs(policy) {
   349  		ci.Policies[resNsName] = policy
   350  		return append(changes, Change{Op: AddOrUpdate, Resource: policy}), problems
   351  	}
   352  	policy.IsValid = false
   353  	policy.ErrorMsg = missingUserSigErrorMsg
   354  	ci.Policies[resNsName] = policy
   355  	return append(changes, Change{Op: Delete, Resource: policy}),
   356  		append(problems, Problem{Object: policyObj, Reason: "Rejected", Message: missingUserSigErrorMsg})
   357  }
   358  
   359  // AddOrUpdateLogConf adds or updates App Protect Log Configuration to App Protect Configuration
   360  func (ci *ConfigurationImpl) AddOrUpdateLogConf(logconfObj *unstructured.Unstructured) (changes []Change, problems []Problem) {
   361  	resNsName := GetNsName(logconfObj)
   362  	logConf, err := createAppProtectLogConfEx(logconfObj)
   363  	ci.LogConfs[resNsName] = logConf
   364  	if err != nil {
   365  		return append(changes, Change{Op: Delete, Resource: logConf}),
   366  			append(problems, Problem{Object: logconfObj, Reason: "Rejected", Message: err.Error()})
   367  	}
   368  	return append(changes, Change{Op: AddOrUpdate, Resource: logConf}), problems
   369  }
   370  
   371  // AddOrUpdateUserSig adds or updates App Protect User Defined Signature to App Protect Configuration
   372  func (ci *ConfigurationImpl) AddOrUpdateUserSig(userSigObj *unstructured.Unstructured) (change UserSigChange, problems []Problem) {
   373  	resNsName := GetNsName(userSigObj)
   374  	userSig, err := createAppProtectUserSigEx(userSigObj)
   375  	ci.UserSigs[resNsName] = userSig
   376  	if err != nil {
   377  		problems = append(problems, Problem{Object: userSigObj, Reason: "Rejected", Message: err.Error()})
   378  	}
   379  	change.UserSigs = append(change.UserSigs, userSigObj)
   380  	ci.buildUserSigChangeAndProblems(&problems, &change)
   381  
   382  	return change, problems
   383  }
   384  
   385  // GetAppResource returns a pointer to an App Protect resource
   386  func (ci *ConfigurationImpl) GetAppResource(kind, key string) (*unstructured.Unstructured, error) {
   387  	switch kind {
   388  	case PolicyGVK.Kind:
   389  		if obj, ok := ci.Policies[key]; ok {
   390  			if obj.IsValid {
   391  				return obj.Obj, nil
   392  			}
   393  			return nil, fmt.Errorf(obj.ErrorMsg)
   394  		}
   395  		return nil, fmt.Errorf("App Protect Policy %s not found", key)
   396  	case LogConfGVK.Kind:
   397  		if obj, ok := ci.LogConfs[key]; ok {
   398  			if obj.IsValid {
   399  				return obj.Obj, nil
   400  			}
   401  			return nil, fmt.Errorf(obj.ErrorMsg)
   402  		}
   403  		return nil, fmt.Errorf("App Protect LogConf %s not found", key)
   404  	case UserSigGVK.Kind:
   405  		if obj, ok := ci.UserSigs[key]; ok {
   406  			if obj.IsValid {
   407  				return obj.Obj, nil
   408  			}
   409  			return nil, fmt.Errorf(obj.ErrorMsg)
   410  		}
   411  		return nil, fmt.Errorf("App Protect UserSig %s not found", key)
   412  	}
   413  	return nil, fmt.Errorf("Unknown App Protect resource kind %s", kind)
   414  }
   415  
   416  // DeletePolicy deletes an App Protect Policy from App Protect Configuration
   417  func (ci *ConfigurationImpl) DeletePolicy(key string) (changes []Change, problems []Problem) {
   418  	if _, has := ci.Policies[key]; has {
   419  		change := Change{Op: Delete, Resource: ci.Policies[key]}
   420  		delete(ci.Policies, key)
   421  		return append(changes, change), problems
   422  	}
   423  	return changes, problems
   424  }
   425  
   426  // DeleteLogConf deletes an App Protect Log Configuration from App Protect Configuration
   427  func (ci *ConfigurationImpl) DeleteLogConf(key string) (changes []Change, problems []Problem) {
   428  	if _, has := ci.LogConfs[key]; has {
   429  		change := Change{Op: Delete, Resource: ci.LogConfs[key]}
   430  		delete(ci.LogConfs, key)
   431  		return append(changes, change), problems
   432  	}
   433  	return changes, problems
   434  }
   435  
   436  // DeleteUserSig deletes an App Protect User Defined Signature from App Protect Configuration
   437  func (ci *ConfigurationImpl) DeleteUserSig(key string) (change UserSigChange, problems []Problem) {
   438  	if _, has := ci.UserSigs[key]; has {
   439  		change.UserSigs = append(change.UserSigs, ci.UserSigs[key].Obj)
   440  		delete(ci.UserSigs, key)
   441  		ci.buildUserSigChangeAndProblems(&problems, &change)
   442  	}
   443  	return change, problems
   444  }
   445  
   446  func (ci *ConfigurationImpl) detectDuplicateTags() (outcome [][]*UserSigEx) {
   447  	tmp := make(map[string][]*UserSigEx)
   448  	for _, sig := range ci.UserSigs {
   449  		if val, has := tmp[sig.Tag]; has {
   450  			if sig.ErrorMsg != failedValidationErrorMsg {
   451  				tmp[sig.Tag] = append(val, sig)
   452  			}
   453  		} else {
   454  			if sig.ErrorMsg != failedValidationErrorMsg {
   455  				tmp[sig.Tag] = []*UserSigEx{sig}
   456  			}
   457  		}
   458  	}
   459  	for key, vals := range tmp {
   460  		if key != "" {
   461  			outcome = append(outcome, vals)
   462  		}
   463  	}
   464  	return outcome
   465  }
   466  
   467  // reconcileUserSigs verifies if tags defined in uds resources are unique
   468  func (ci *ConfigurationImpl) reconcileUserSigs() (changes []Change, problems []Problem) {
   469  	dupTag := ci.detectDuplicateTags()
   470  	for _, sigs := range dupTag {
   471  		sort.Sort(appProtectUserSigSlice(sigs))
   472  		winner := sigs[0]
   473  		if !winner.IsValid {
   474  			winner.setValid()
   475  			change := Change{Op: AddOrUpdate, Resource: winner}
   476  			changes = append(changes, change)
   477  		}
   478  		for _, sig := range sigs[1:] {
   479  			if sig.IsValid {
   480  				sig.setInvalid(duplicatedTagsErrorMsg)
   481  				looserProblem := Problem{Object: sig.Obj, Reason: "Rejected", Message: duplicatedTagsErrorMsg}
   482  				looserChange := Change{Op: Delete, Resource: sig}
   483  				changes = append(changes, looserChange)
   484  				problems = append(problems, looserProblem)
   485  			}
   486  		}
   487  	}
   488  	return changes, problems
   489  }
   490  
   491  func (ci *ConfigurationImpl) verifyPolicies() (changes []Change, problems []Problem) {
   492  	for _, pol := range ci.Policies {
   493  		if !pol.IsValid && pol.ErrorMsg == missingUserSigErrorMsg {
   494  			if ci.verifyPolicyAgainstUserSigs(pol) {
   495  				pol.setValid()
   496  				change := Change{Op: AddOrUpdate, Resource: pol}
   497  				changes = append(changes, change)
   498  			}
   499  		}
   500  		if pol.IsValid {
   501  			if !ci.verifyPolicyAgainstUserSigs(pol) {
   502  				pol.setInvalid(missingUserSigErrorMsg)
   503  				polProb := Problem{Object: pol.Obj, Reason: "Rejected", Message: missingUserSigErrorMsg}
   504  				polCh := Change{Op: Delete, Resource: pol}
   505  				changes = append(changes, polCh)
   506  				problems = append(problems, polProb)
   507  			}
   508  		}
   509  	}
   510  	return changes, problems
   511  }
   512  
   513  func (ci *ConfigurationImpl) getAllUserSigObjects() []*unstructured.Unstructured {
   514  	out := []*unstructured.Unstructured{}
   515  	for _, uds := range ci.UserSigs {
   516  		if uds.IsValid {
   517  			out = append(out, uds.Obj)
   518  		}
   519  	}
   520  	return out
   521  }
   522  
   523  func (ci *ConfigurationImpl) buildUserSigChangeAndProblems(problems *[]Problem, udschange *UserSigChange) {
   524  	reconChanges, reconProblems := ci.reconcileUserSigs()
   525  	verChanges, verProblems := ci.verifyPolicies()
   526  	*problems = append(*problems, reconProblems...)
   527  	*problems = append(*problems, verProblems...)
   528  	reconChanges = append(reconChanges, verChanges...)
   529  	for _, cha := range reconChanges {
   530  		switch impl := cha.Resource.(type) {
   531  		case *PolicyEx:
   532  			if cha.Op == Delete {
   533  				udschange.PolicyDeletions = append(udschange.PolicyDeletions, impl.Obj)
   534  			}
   535  			if cha.Op == AddOrUpdate {
   536  				udschange.PolicyAddsOrUpdates = append(udschange.PolicyAddsOrUpdates, impl.Obj)
   537  			}
   538  		case *UserSigEx:
   539  			continue
   540  		}
   541  	}
   542  	udschange.UserSigs = ci.getAllUserSigObjects()
   543  }
   544  
   545  // FakeConfiguration holds representations of fake App Protect cluster resources
   546  type FakeConfiguration struct {
   547  	Policies map[string]*PolicyEx
   548  	LogConfs map[string]*LogConfEx
   549  	UserSigs map[string]*UserSigEx
   550  }
   551  
   552  // NewFakeConfiguration creates a new App Protect Configuration
   553  func NewFakeConfiguration() Configuration {
   554  	return &FakeConfiguration{
   555  		Policies: make(map[string]*PolicyEx),
   556  		LogConfs: make(map[string]*LogConfEx),
   557  		UserSigs: make(map[string]*UserSigEx),
   558  	}
   559  }
   560  
   561  // AddOrUpdatePolicy adds or updates an App Protect Policy to App Protect Configuration
   562  func (fc *FakeConfiguration) AddOrUpdatePolicy(policyObj *unstructured.Unstructured) (changes []Change, problems []Problem) {
   563  	resNsName := GetNsName(policyObj)
   564  	policy := &PolicyEx{
   565  		Obj:     policyObj,
   566  		IsValid: true,
   567  	}
   568  	fc.Policies[resNsName] = policy
   569  	return changes, problems
   570  }
   571  
   572  // AddOrUpdateLogConf adds or updates App Protect Log Configuration to App Protect Configuration
   573  func (fc *FakeConfiguration) AddOrUpdateLogConf(logConfObj *unstructured.Unstructured) (changes []Change, problems []Problem) {
   574  	resNsName := GetNsName(logConfObj)
   575  	logConf := &LogConfEx{
   576  		Obj:     logConfObj,
   577  		IsValid: true,
   578  	}
   579  	fc.LogConfs[resNsName] = logConf
   580  	return changes, problems
   581  }
   582  
   583  // AddOrUpdateUserSig adds or updates App Protect User Defined Signature to App Protect Configuration
   584  func (fc *FakeConfiguration) AddOrUpdateUserSig(userSigObj *unstructured.Unstructured) (change UserSigChange, problems []Problem) {
   585  	return change, problems
   586  }
   587  
   588  // GetAppResource returns a pointer to an App Protect resource
   589  func (fc *FakeConfiguration) GetAppResource(kind, key string) (*unstructured.Unstructured, error) {
   590  	switch kind {
   591  	case PolicyGVK.Kind:
   592  		if obj, ok := fc.Policies[key]; ok {
   593  			return obj.Obj, nil
   594  		}
   595  		return nil, fmt.Errorf("App Protect Policy %s not found", key)
   596  	case LogConfGVK.Kind:
   597  		if obj, ok := fc.LogConfs[key]; ok {
   598  			return obj.Obj, nil
   599  		}
   600  		return nil, fmt.Errorf("App Protect LogConf %s not found", key)
   601  	}
   602  	return nil, fmt.Errorf("Unknown App Protect resource kind %s", kind)
   603  }
   604  
   605  // DeletePolicy deletes an App Protect Policy from App Protect Configuration
   606  func (fc *FakeConfiguration) DeletePolicy(key string) (changes []Change, problems []Problem) {
   607  	return changes, problems
   608  }
   609  
   610  // DeleteLogConf deletes an App Protect Log Configuration from App Protect Configuration
   611  func (fc *FakeConfiguration) DeleteLogConf(key string) (changes []Change, problems []Problem) {
   612  	return changes, problems
   613  }
   614  
   615  // DeleteUserSig deletes an App Protect User Defined Signature from App Protect Configuration
   616  func (fc *FakeConfiguration) DeleteUserSig(key string) (change UserSigChange, problems []Problem) {
   617  	return change, problems
   618  }