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