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 }