github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/appsec/rule.go (about)

     1  package appsec
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  
     9  	validation "github.com/go-ozzo/ozzo-validation/v4"
    10  )
    11  
    12  type (
    13  	// The Rule interface supports retrieving and modifying the rules in a policy together with their
    14  	// actions, conditions and exceptions, or the action, condition and exceptions of a specific rule.
    15  	Rule interface {
    16  		// GetRules returns the action taken for each rule in a policy.
    17  		//
    18  		// See: https://techdocs.akamai.com/application-security/reference/get-policy-rules
    19  		GetRules(ctx context.Context, params GetRulesRequest) (*GetRulesResponse, error)
    20  
    21  		// GetRule returns the action a rule takes when triggered with conditions and exceptions.
    22  		//
    23  		// See: https://techdocs.akamai.com/application-security/reference/get-rule-condition-exception-1
    24  		// See: https://techdocs.akamai.com/application-security/reference/get-rule-1
    25  		GetRule(ctx context.Context, params GetRuleRequest) (*GetRuleResponse, error)
    26  
    27  		// UpdateRule updates what action a rule takes when it's triggered.
    28  		//
    29  		// See: https://techdocs.akamai.com/application-security/reference/put-rule-1
    30  		UpdateRule(ctx context.Context, params UpdateRuleRequest) (*UpdateRuleResponse, error)
    31  
    32  		// UpdateRuleConditionException updates a rule's conditions and exceptions.
    33  		//
    34  		// See: https://techdocs.akamai.com/application-security/reference/put-rule-condition-exception-1
    35  		UpdateRuleConditionException(ctx context.Context, params UpdateConditionExceptionRequest) (*UpdateConditionExceptionResponse, error)
    36  	}
    37  
    38  	// GetRulesRequest is used to retrieve the rules for a configuration and policy, together with their actions and condition and exception information.
    39  	GetRulesRequest struct {
    40  		ConfigID int    `json:"-"`
    41  		Version  int    `json:"-"`
    42  		PolicyID string `json:"-"`
    43  		RuleID   int    `json:"-"`
    44  	}
    45  
    46  	// GetRulesResponse is returned from a call to GetRules.
    47  	GetRulesResponse struct {
    48  		Rules []struct {
    49  			ID                 int                     `json:"id,omitempty"`
    50  			Action             string                  `json:"action,omitempty"`
    51  			ConditionException *RuleConditionException `json:"conditionException,omitempty"`
    52  		} `json:"ruleActions,omitempty"`
    53  	}
    54  
    55  	// GetRuleRequest is used to retrieve a rule together with its action and its condition and exception information.
    56  	GetRuleRequest struct {
    57  		ConfigID int    `json:"-"`
    58  		Version  int    `json:"-"`
    59  		PolicyID string `json:"-"`
    60  		RuleID   int    `json:"-"`
    61  	}
    62  
    63  	// GetRuleResponse is returned from a call to GetRule.
    64  	GetRuleResponse struct {
    65  		Action             string                  `json:"action,omitempty"`
    66  		ConditionException *RuleConditionException `json:"conditionException,omitempty"`
    67  	}
    68  
    69  	// UpdateRuleRequest is used to modify the settings for a rule.
    70  	UpdateRuleRequest struct {
    71  		ConfigID       int             `json:"-"`
    72  		Version        int             `json:"-"`
    73  		PolicyID       string          `json:"-"`
    74  		RuleID         int             `json:"-"`
    75  		Action         string          `json:"action"`
    76  		JsonPayloadRaw json.RawMessage `json:"conditionException,omitempty"`
    77  	}
    78  
    79  	// UpdateRuleResponse is returned from a call to UpdateRule.
    80  	UpdateRuleResponse struct {
    81  		Action             string                  `json:"action,omitempty"`
    82  		ConditionException *RuleConditionException `json:"conditionException,omitempty"`
    83  	}
    84  
    85  	// AdvancedExceptions is used to describe advanced exceptions used in Adaptive Security Engine(ASE) rules.
    86  	AdvancedExceptions AttackGroupAdvancedExceptions
    87  
    88  	// RuleConditionException is used to describe the conditions and exceptions for a rule.
    89  	RuleConditionException struct {
    90  		Conditions             *RuleConditions     `json:"conditions,omitempty"`
    91  		Exception              *RuleException      `json:"exception,omitempty"`
    92  		AdvancedExceptionsList *AdvancedExceptions `json:"advancedExceptions,omitempty"`
    93  	}
    94  
    95  	// RuleConditions is used to describe the conditions for a rule.
    96  	RuleConditions []struct {
    97  		Type          string   `json:"type,omitempty"`
    98  		Extensions    []string `json:"extensions,omitempty"`
    99  		Filenames     []string `json:"filenames,omitempty"`
   100  		Hosts         []string `json:"hosts,omitempty"`
   101  		Ips           []string `json:"ips,omitempty"`
   102  		Methods       []string `json:"methods,omitempty"`
   103  		Paths         []string `json:"paths,omitempty"`
   104  		Header        string   `json:"header,omitempty"`
   105  		CaseSensitive bool     `json:"caseSensitive,omitempty"`
   106  		Name          string   `json:"name,omitempty"`
   107  		NameCase      bool     `json:"nameCase,omitempty"`
   108  		PositiveMatch bool     `json:"positiveMatch"`
   109  		Value         string   `json:"value,omitempty"`
   110  		Wildcard      bool     `json:"wildcard,omitempty"`
   111  		ValueCase     bool     `json:"valueCase,omitempty"`
   112  		ValueWildcard bool     `json:"valueWildcard,omitempty"`
   113  		UseHeaders    bool     `json:"useHeaders,omitempty"`
   114  	}
   115  
   116  	// RuleException is used to describe the exceptions for a rule.
   117  	RuleException struct {
   118  		AnyHeaderCookieOrParam                  []string                                 `json:"anyHeaderCookieOrParam,omitempty"`
   119  		HeaderCookieOrParamValues               []string                                 `json:"headerCookieOrParamValues,omitempty"`
   120  		SpecificHeaderCookieOrParamNameValue    *SpecificHeaderCookieOrParamNameValuePtr `json:"specificHeaderCookieOrParamNameValue,omitempty"`
   121  		SpecificHeaderCookieOrParamNames        *SpecificHeaderCookieOrParamNamesPtr     `json:"specificHeaderCookieOrParamNames,omitempty"`
   122  		SpecificHeaderCookieOrParamPrefix       *SpecificHeaderCookieOrParamPrefixPtr    `json:"specificHeaderCookieOrParamPrefix,omitempty"`
   123  		SpecificHeaderCookieParamXMLOrJSONNames *SpecificHeaderCookieParamXMLOrJSONNames `json:"specificHeaderCookieParamXmlOrJsonNames,omitempty"`
   124  	}
   125  
   126  	// SpecificHeaderCookieOrParamNamesPtr is used as part of condition and exception information for a rule.
   127  	SpecificHeaderCookieOrParamNamesPtr []struct {
   128  		Names    []string `json:"names,omitempty"`
   129  		Selector string   `json:"selector,omitempty"`
   130  	}
   131  
   132  	// SpecificHeaderCookieOrParamPrefixPtr is used as part of condition and exception information for a rule.
   133  	SpecificHeaderCookieOrParamPrefixPtr struct {
   134  		Prefix   string `json:"prefix,omitempty"`
   135  		Selector string `json:"selector,omitempty"`
   136  	}
   137  
   138  	// SpecificHeaderCookieOrParamNameValuePtr is used as part of condition and exception information for a rule.
   139  	SpecificHeaderCookieOrParamNameValuePtr struct {
   140  		Name     string `json:"name,omitempty"`
   141  		Selector string `json:"selector,omitempty"`
   142  		Value    string `json:"value,omitempty"`
   143  	}
   144  
   145  	// SpecificHeaderCookieParamXMLOrJSONNames is used as part of condition and exception information for an ASE rule.
   146  	SpecificHeaderCookieParamXMLOrJSONNames AttackGroupSpecificHeaderCookieParamXMLOrJSONNames
   147  
   148  	// UpdateConditionExceptionRequest is used to update the condition and exception information for a rule.
   149  	UpdateConditionExceptionRequest struct {
   150  		ConfigID               int                 `json:"-"`
   151  		Version                int                 `json:"-"`
   152  		PolicyID               string              `json:"-"`
   153  		RuleID                 int                 `json:"-"`
   154  		Conditions             *RuleConditions     `json:"conditions,omitempty"`
   155  		Exception              *RuleException      `json:"exception,omitempty"`
   156  		AdvancedExceptionsList *AdvancedExceptions `json:"advancedExceptions,omitempty"`
   157  	}
   158  
   159  	// UpdateConditionExceptionResponse is returned from a call to UpdateConditionException.
   160  	UpdateConditionExceptionResponse RuleConditionException
   161  )
   162  
   163  // IsEmptyConditionException checks whether a rule's condition and exception information is empty.
   164  func (r *GetRuleResponse) IsEmptyConditionException() bool {
   165  	return r.ConditionException == nil
   166  }
   167  
   168  // Validate validates a GetRuleRequest.
   169  func (v GetRuleRequest) Validate() error {
   170  	return validation.Errors{
   171  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   172  		"Version":  validation.Validate(v.Version, validation.Required),
   173  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   174  		"RuleID":   validation.Validate(v.RuleID, validation.Required),
   175  	}.Filter()
   176  }
   177  
   178  // Validate validates a GetRulesRequest.
   179  func (v GetRulesRequest) Validate() error {
   180  	return validation.Errors{
   181  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   182  		"Version":  validation.Validate(v.Version, validation.Required),
   183  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   184  	}.Filter()
   185  }
   186  
   187  // Validate validates an UpdateRuleRequest.
   188  func (v UpdateRuleRequest) Validate() error {
   189  	return validation.Errors{
   190  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   191  		"Version":  validation.Validate(v.Version, validation.Required),
   192  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   193  		"RuleID":   validation.Validate(v.RuleID, validation.Required),
   194  	}.Filter()
   195  }
   196  
   197  // Validate validates an UpdateConditionExceptionRequest.
   198  func (v UpdateConditionExceptionRequest) Validate() error {
   199  	return validation.Errors{
   200  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   201  		"Version":  validation.Validate(v.Version, validation.Required),
   202  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   203  		"RuleID":   validation.Validate(v.RuleID, validation.Required),
   204  	}.Filter()
   205  }
   206  
   207  func (p *appsec) GetRule(ctx context.Context, params GetRuleRequest) (*GetRuleResponse, error) {
   208  	logger := p.Log(ctx)
   209  	logger.Debug("GetRule")
   210  
   211  	if err := params.Validate(); err != nil {
   212  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   213  	}
   214  
   215  	uri := fmt.Sprintf(
   216  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d?includeConditionException=true",
   217  		params.ConfigID,
   218  		params.Version,
   219  		params.PolicyID,
   220  		params.RuleID)
   221  
   222  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   223  	if err != nil {
   224  		return nil, fmt.Errorf("failed to create GetRule request: %w", err)
   225  	}
   226  
   227  	var result GetRuleResponse
   228  	resp, err := p.Exec(req, &result)
   229  	if err != nil {
   230  		return nil, fmt.Errorf("get rule request failed: %w", err)
   231  	}
   232  	if resp.StatusCode != http.StatusOK {
   233  		return nil, p.Error(resp)
   234  	}
   235  
   236  	return &result, nil
   237  }
   238  
   239  func (p *appsec) GetRules(ctx context.Context, params GetRulesRequest) (*GetRulesResponse, error) {
   240  	logger := p.Log(ctx)
   241  	logger.Debug("GetRules")
   242  
   243  	if err := params.Validate(); err != nil {
   244  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   245  	}
   246  
   247  	uri := fmt.Sprintf(
   248  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules?includeConditionException=true",
   249  		params.ConfigID,
   250  		params.Version,
   251  		params.PolicyID)
   252  
   253  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   254  	if err != nil {
   255  		return nil, fmt.Errorf("failed to create GetRules request: %w", err)
   256  	}
   257  
   258  	var result GetRulesResponse
   259  	resp, err := p.Exec(req, &result)
   260  	if err != nil {
   261  		return nil, fmt.Errorf("get rules request failed: %w", err)
   262  	}
   263  	if resp.StatusCode != http.StatusOK {
   264  		return nil, p.Error(resp)
   265  	}
   266  
   267  	if params.RuleID != 0 {
   268  		var filteredResult GetRulesResponse
   269  		for _, val := range result.Rules {
   270  			if val.ID == params.RuleID {
   271  				filteredResult.Rules = append(filteredResult.Rules, val)
   272  			}
   273  		}
   274  		return &filteredResult, nil
   275  	}
   276  
   277  	return &result, nil
   278  }
   279  
   280  func (p *appsec) UpdateRule(ctx context.Context, params UpdateRuleRequest) (*UpdateRuleResponse, error) {
   281  	logger := p.Log(ctx)
   282  	logger.Debug("UpdateRule")
   283  
   284  	if err := params.Validate(); err != nil {
   285  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   286  	}
   287  
   288  	uri := fmt.Sprintf(
   289  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d/action-condition-exception",
   290  		params.ConfigID,
   291  		params.Version,
   292  		params.PolicyID,
   293  		params.RuleID,
   294  	)
   295  
   296  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil)
   297  	if err != nil {
   298  		return nil, fmt.Errorf("failed to create UpdateRule request: %w", err)
   299  	}
   300  
   301  	var result UpdateRuleResponse
   302  	resp, err := p.Exec(req, &result, params)
   303  	if err != nil {
   304  		return nil, fmt.Errorf("update rule request failed: %w", err)
   305  	}
   306  	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
   307  		return nil, p.Error(resp)
   308  	}
   309  
   310  	return &result, nil
   311  }
   312  
   313  func (p *appsec) UpdateRuleConditionException(ctx context.Context, params UpdateConditionExceptionRequest) (*UpdateConditionExceptionResponse, error) {
   314  	logger := p.Log(ctx)
   315  	logger.Debug("UpdateRuleConditionException")
   316  
   317  	if err := params.Validate(); err != nil {
   318  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   319  	}
   320  
   321  	uri := fmt.Sprintf(
   322  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d/condition-exception",
   323  		params.ConfigID,
   324  		params.Version,
   325  		params.PolicyID,
   326  		params.RuleID,
   327  	)
   328  
   329  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil)
   330  	if err != nil {
   331  		return nil, fmt.Errorf("failed to create UpdateRuleConditionException request: %w", err)
   332  	}
   333  
   334  	var result UpdateConditionExceptionResponse
   335  	resp, err := p.Exec(req, &result, params)
   336  	if err != nil {
   337  		return nil, fmt.Errorf("update rule condition exception request failed: %w", err)
   338  	}
   339  	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
   340  		return nil, p.Error(resp)
   341  	}
   342  
   343  	return &result, nil
   344  }