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 }