github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/appsec/attack_group.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 AttackGroup interface supports retrieving and updating attack groups along with their
    14  	// associated actions, conditions, and exceptions.
    15  	//
    16  	// https://developer.akamai.com/api/cloud_security/application_security/v1.html#attackgroup
    17  	AttackGroup interface {
    18  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#getattackgroups
    19  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#getattackgroupconditionexception
    20  		GetAttackGroups(ctx context.Context, params GetAttackGroupsRequest) (*GetAttackGroupsResponse, error)
    21  
    22  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#getattackgroup
    23  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#getattackgroupconditionexception
    24  		GetAttackGroup(ctx context.Context, params GetAttackGroupRequest) (*GetAttackGroupResponse, error)
    25  
    26  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#putattackgroup
    27  		// https://developer.akamai.com/api/cloud_security/application_security/v1.html#putattackgroupconditionexception
    28  		UpdateAttackGroup(ctx context.Context, params UpdateAttackGroupRequest) (*UpdateAttackGroupResponse, error)
    29  	}
    30  
    31  	// AttackGroupConditionException describes an attack group's condition and exception information.
    32  	AttackGroupConditionException struct {
    33  		AdvancedExceptionsList *AttackGroupAdvancedExceptions `json:"advancedExceptions,omitempty"`
    34  		Exception              *AttackGroupException          `json:"exception,omitempty"`
    35  	}
    36  
    37  	// AttackGroupAdvancedExceptions describes an attack group's advanced exception information.
    38  	AttackGroupAdvancedExceptions struct {
    39  		ConditionOperator                       string                                                      `json:"conditionOperator,omitempty"`
    40  		Conditions                              *AttackGroupConditions                                      `json:"conditions,omitempty"`
    41  		HeaderCookieOrParamValues               *AttackGroupHeaderCookieOrParamValuesAdvanced               `json:"headerCookieOrParamValues,omitempty"`
    42  		SpecificHeaderCookieOrParamNameValue    *AttackGroupSpecificHeaderCookieOrParamNameValAdvanced      `json:"specificHeaderCookieOrParamNameValue,omitempty"`
    43  		SpecificHeaderCookieParamXMLOrJSONNames *AttackGroupSpecificHeaderCookieParamXMLOrJSONNamesAdvanced `json:"specificHeaderCookieParamXmlOrJsonNames,omitempty"`
    44  	}
    45  
    46  	// AttackGroupConditions describes an attack group's condition information.
    47  	AttackGroupConditions []struct {
    48  		Type          string   `json:"type,omitempty"`
    49  		Extensions    []string `json:"extensions,omitempty"`
    50  		Filenames     []string `json:"filenames,omitempty"`
    51  		Hosts         []string `json:"hosts,omitempty"`
    52  		Ips           []string `json:"ips,omitempty"`
    53  		Methods       []string `json:"methods,omitempty"`
    54  		Paths         []string `json:"paths,omitempty"`
    55  		Header        string   `json:"header,omitempty"`
    56  		CaseSensitive bool     `json:"caseSensitive,omitempty"`
    57  		Name          string   `json:"name,omitempty"`
    58  		NameCase      bool     `json:"nameCase,omitempty"`
    59  		PositiveMatch bool     `json:"positiveMatch"`
    60  		Value         string   `json:"value,omitempty"`
    61  		Wildcard      bool     `json:"wildcard,omitempty"`
    62  		ValueCase     bool     `json:"valueCase,omitempty"`
    63  		ValueWildcard bool     `json:"valueWildcard,omitempty"`
    64  		UseHeaders    bool     `json:"useHeaders,omitempty"`
    65  	}
    66  
    67  	// AttackGroupAdvancedCriteria describes the hostname and path criteria used to limit the scope of an exception.
    68  	AttackGroupAdvancedCriteria []struct {
    69  		Hostnames []string `json:"hostnames,omitempty"`
    70  		Names     []string `json:"names,omitempty"`
    71  		Paths     []string `json:"paths,omitempty"`
    72  		Values    []string `json:"values,omitempty"`
    73  	}
    74  
    75  	// AttackGroupSpecificHeaderCookieOrParamNameValAdvanced describes the excepted name-value pairs in a request.
    76  	AttackGroupSpecificHeaderCookieOrParamNameValAdvanced []struct {
    77  		Criteria    *AttackGroupAdvancedCriteria `json:"criteria,omitempty"`
    78  		NamesValues []struct {
    79  			Names  []string `json:"names"`
    80  			Values []string `json:"values"`
    81  		} `json:"namesValues"`
    82  		Selector      string `json:"selector"`
    83  		ValueWildcard bool   `json:"valueWildcard"`
    84  		Wildcard      bool   `json:"wildcard"`
    85  	}
    86  
    87  	// AttackGroupSpecificHeaderCookieParamXMLOrJSONNamesAdvanced describes the advanced exception members that allow you to conditionally exclude requests from inspection.
    88  	AttackGroupSpecificHeaderCookieParamXMLOrJSONNamesAdvanced []struct {
    89  		Criteria *AttackGroupAdvancedCriteria `json:"criteria,omitempty"`
    90  		Names    []string                     `json:"names,omitempty"`
    91  		Selector string                       `json:"selector,omitempty"`
    92  		Wildcard bool                         `json:"wildcard,omitempty"`
    93  	}
    94  
    95  	// AttackGroupHeaderCookieOrParamValuesAdvanced describes the list of excepted values in headers, cookies, or query parameters.
    96  	AttackGroupHeaderCookieOrParamValuesAdvanced []struct {
    97  		Criteria      *AttackGroupAdvancedCriteria `json:"criteria,omitempty"`
    98  		ValueWildcard bool                         `json:"valueWildcard"`
    99  		Values        []string                     `json:"values,omitempty"`
   100  	}
   101  
   102  	// AttackGroupException is used to describe an exception that can be used to conditionally exclude requests from inspection.
   103  	AttackGroupException struct {
   104  		SpecificHeaderCookieParamXMLOrJSONNames *AttackGroupSpecificHeaderCookieParamXMLOrJSONNames `json:"specificHeaderCookieParamXmlOrJsonNames,omitempty"`
   105  	}
   106  
   107  	// AttackGroupSpecificHeaderCookieParamXMLOrJSONNames describes the advanced exception members that can be used to conditionally exclude requests from inspection.
   108  	AttackGroupSpecificHeaderCookieParamXMLOrJSONNames []struct {
   109  		Names    []string `json:"names,omitempty"`
   110  		Selector string   `json:"selector,omitempty"`
   111  		Wildcard bool     `json:"wildcard,omitempty"`
   112  	}
   113  
   114  	// GetAttackGroupsRequest is used to retrieve a list of attack groups with their associated actions.
   115  	GetAttackGroupsRequest struct {
   116  		ConfigID int    `json:"-"`
   117  		Version  int    `json:"-"`
   118  		PolicyID string `json:"-"`
   119  		Group    string `json:"group,omitempty"`
   120  	}
   121  
   122  	// GetAttackGroupsResponse is returned from a call to GetAttackGroups.
   123  	GetAttackGroupsResponse struct {
   124  		AttackGroups []struct {
   125  			Group              string                         `json:"group,omitempty"`
   126  			Action             string                         `json:"action,omitempty"`
   127  			ConditionException *AttackGroupConditionException `json:"conditionException,omitempty"`
   128  		} `json:"attackGroupActions,omitempty"`
   129  	}
   130  
   131  	// GetAttackGroupRequest is used to retrieve a list of attack groups with their associated actions.
   132  	GetAttackGroupRequest struct {
   133  		ConfigID int    `json:"-"`
   134  		Version  int    `json:"-"`
   135  		PolicyID string `json:"-"`
   136  		Group    string `json:"group"`
   137  	}
   138  
   139  	// GetAttackGroupResponse is returned from a call to GetAttackGroup.
   140  	GetAttackGroupResponse struct {
   141  		Action             string                         `json:"action,omitempty"`
   142  		ConditionException *AttackGroupConditionException `json:"conditionException,omitempty"`
   143  	}
   144  
   145  	// UpdateAttackGroupRequest is used to modify what action to take when an attack group’s rule triggers.
   146  	UpdateAttackGroupRequest struct {
   147  		ConfigID       int             `json:"-"`
   148  		Version        int             `json:"-"`
   149  		PolicyID       string          `json:"-"`
   150  		Group          string          `json:"-"`
   151  		Action         string          `json:"action"`
   152  		JsonPayloadRaw json.RawMessage `json:"conditionException,omitempty"`
   153  	}
   154  
   155  	// UpdateAttackGroupResponse is returned from a call to UpdateAttackGroup.
   156  	UpdateAttackGroupResponse struct {
   157  		Action             string                         `json:"action,omitempty"`
   158  		ConditionException *AttackGroupConditionException `json:"conditionException,omitempty"`
   159  	}
   160  )
   161  
   162  // IsEmptyConditionException checks whether an attack group's ConditionException field is empty.
   163  func (r GetAttackGroupResponse) IsEmptyConditionException() bool {
   164  	return r.ConditionException == nil
   165  }
   166  
   167  // Validate validates a GetAttackGroupConditionExceptionRequest.
   168  func (v GetAttackGroupRequest) Validate() error {
   169  	return validation.Errors{
   170  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   171  		"Version":  validation.Validate(v.Version, validation.Required),
   172  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   173  	}.Filter()
   174  }
   175  
   176  // Validate validates a GetAttackGroupConditionExceptionsRequest.
   177  func (v GetAttackGroupsRequest) Validate() error {
   178  	return validation.Errors{
   179  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   180  		"Version":  validation.Validate(v.Version, validation.Required),
   181  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   182  	}.Filter()
   183  }
   184  
   185  // Validate validates an UpdateAttackGroupConditionExceptionRequest.
   186  func (v UpdateAttackGroupRequest) Validate() error {
   187  	return validation.Errors{
   188  		"ConfigID": validation.Validate(v.ConfigID, validation.Required),
   189  		"Version":  validation.Validate(v.Version, validation.Required),
   190  		"PolicyID": validation.Validate(v.PolicyID, validation.Required),
   191  	}.Filter()
   192  }
   193  
   194  func (p *appsec) GetAttackGroup(ctx context.Context, params GetAttackGroupRequest) (*GetAttackGroupResponse, error) {
   195  	logger := p.Log(ctx)
   196  	logger.Debug("GetAttackGroup")
   197  
   198  	if err := params.Validate(); err != nil {
   199  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   200  	}
   201  
   202  	uri := fmt.Sprintf(
   203  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/attack-groups/%s?includeConditionException=true",
   204  		params.ConfigID,
   205  		params.Version,
   206  		params.PolicyID,
   207  		params.Group)
   208  
   209  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   210  	if err != nil {
   211  		return nil, fmt.Errorf("failed to create GetAttackGroup request: %w", err)
   212  	}
   213  
   214  	var result GetAttackGroupResponse
   215  	resp, err := p.Exec(req, &result)
   216  	if err != nil {
   217  		return nil, fmt.Errorf("get attack group request failed: %w", err)
   218  	}
   219  	if resp.StatusCode != http.StatusOK {
   220  		return nil, p.Error(resp)
   221  	}
   222  
   223  	return &result, nil
   224  }
   225  
   226  func (p *appsec) GetAttackGroups(ctx context.Context, params GetAttackGroupsRequest) (*GetAttackGroupsResponse, error) {
   227  	logger := p.Log(ctx)
   228  	logger.Debug("GetAttackGroups")
   229  
   230  	if err := params.Validate(); err != nil {
   231  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   232  	}
   233  
   234  	uri := fmt.Sprintf(
   235  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/attack-groups?includeConditionException=true",
   236  		params.ConfigID,
   237  		params.Version,
   238  		params.PolicyID)
   239  
   240  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   241  	if err != nil {
   242  		return nil, fmt.Errorf("failed to create GetAttackGroups request: %w", err)
   243  	}
   244  
   245  	var result GetAttackGroupsResponse
   246  	resp, err := p.Exec(req, &result)
   247  	if err != nil {
   248  		return nil, fmt.Errorf("get attack groups request failed: %w", err)
   249  	}
   250  	if resp.StatusCode != http.StatusOK {
   251  		return nil, p.Error(resp)
   252  	}
   253  
   254  	if params.Group != "" {
   255  		var filteredResult GetAttackGroupsResponse
   256  		for k, val := range result.AttackGroups {
   257  			if val.Group == params.Group {
   258  				filteredResult.AttackGroups = append(filteredResult.AttackGroups, result.AttackGroups[k])
   259  			}
   260  		}
   261  		return &filteredResult, nil
   262  	}
   263  
   264  	return &result, nil
   265  }
   266  
   267  func (p *appsec) UpdateAttackGroup(ctx context.Context, params UpdateAttackGroupRequest) (*UpdateAttackGroupResponse, error) {
   268  	logger := p.Log(ctx)
   269  	logger.Debug("UpdateAttackGroup")
   270  
   271  	if err := params.Validate(); err != nil {
   272  		return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error())
   273  	}
   274  
   275  	uri := fmt.Sprintf(
   276  		"/appsec/v1/configs/%d/versions/%d/security-policies/%s/attack-groups/%s/action-condition-exception",
   277  		params.ConfigID,
   278  		params.Version,
   279  		params.PolicyID,
   280  		params.Group,
   281  	)
   282  
   283  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil)
   284  	if err != nil {
   285  		return nil, fmt.Errorf("failed to create UpdateAttackGroup request: %w", err)
   286  	}
   287  
   288  	var result UpdateAttackGroupResponse
   289  	req.Header.Set("Content-Type", "application/json")
   290  	resp, err := p.Exec(req, &result, params)
   291  	if err != nil {
   292  		return nil, fmt.Errorf("update attack group request failed: %w", err)
   293  	}
   294  
   295  	if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
   296  		return nil, p.Error(resp)
   297  	}
   298  
   299  	return &result, nil
   300  }