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