github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/appsec/rate_policy.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 RatePolicy interface supports creating, retrieving, updating and removing rate policies. 14 RatePolicy interface { 15 // GetRatePolicies returns rate policies for a specific security configuration version. 16 // 17 // See: https://techdocs.akamai.com/application-security/reference/get-rate-policies 18 GetRatePolicies(ctx context.Context, params GetRatePoliciesRequest) (*GetRatePoliciesResponse, error) 19 20 // GetRatePolicy returns the specified rate policy. 21 // 22 // See: https://techdocs.akamai.com/application-security/reference/get-rate-policy 23 GetRatePolicy(ctx context.Context, params GetRatePolicyRequest) (*GetRatePolicyResponse, error) 24 25 // CreateRatePolicy creates a new rate policy for a specific configuration version. 26 // 27 // See: https://techdocs.akamai.com/application-security/reference/post-rate-policies 28 CreateRatePolicy(ctx context.Context, params CreateRatePolicyRequest) (*CreateRatePolicyResponse, error) 29 30 // UpdateRatePolicy updates details for a specific rate policy. 31 // 32 // See: https://techdocs.akamai.com/application-security/reference/put-rate-policy 33 UpdateRatePolicy(ctx context.Context, params UpdateRatePolicyRequest) (*UpdateRatePolicyResponse, error) 34 35 // RemoveRatePolicy deletes the specified rate policy. 36 // 37 // See: https://techdocs.akamai.com/application-security/reference/delete-rate-policy 38 RemoveRatePolicy(ctx context.Context, params RemoveRatePolicyRequest) (*RemoveRatePolicyResponse, error) 39 } 40 41 // CreateRatePolicyRequest is used to create a rate policy. 42 CreateRatePolicyRequest struct { 43 ID int `json:"-"` 44 ConfigID int `json:"configId"` 45 ConfigVersion int `json:"configVersion"` 46 JsonPayloadRaw json.RawMessage `json:"-"` 47 } 48 49 // CreateRatePolicyResponse is returned from a call to CreateRatePolicy. 50 CreateRatePolicyResponse struct { 51 ID int `json:"id"` 52 ConfigID int `json:"configId"` 53 ConfigVersion int `json:"configVersion"` 54 MatchType string `json:"matchType"` 55 Type string `json:"type"` 56 Name string `json:"name"` 57 Description string `json:"description"` 58 AverageThreshold int `json:"averageThreshold"` 59 BurstThreshold int `json:"burstThreshold"` 60 BurstWindow int `json:"burstWindow"` 61 ClientIdentifier string `json:"clientIdentifier"` 62 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 63 RequestType string `json:"requestType"` 64 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 65 Path struct { 66 PositiveMatch bool `json:"positiveMatch"` 67 Values []string `json:"values"` 68 } `json:"path"` 69 PathMatchType string `json:"pathMatchType"` 70 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 71 FileExtensions struct { 72 PositiveMatch bool `json:"positiveMatch"` 73 Values []string `json:"values"` 74 } `json:"fileExtensions"` 75 Hosts *RatePoliciesHosts `json:"hosts,omitempty"` 76 Hostnames []string `json:"hostnames"` 77 AdditionalMatchOptions []RatePolicyMatchOption `json:"additionalMatchOptions,omitempty"` 78 Condition *RatePolicyCondition `json:"condition,omitempty"` 79 QueryParameters []struct { 80 Name string `json:"name"` 81 Values []string `json:"values"` 82 PositiveMatch bool `json:"positiveMatch"` 83 ValueInRange bool `json:"valueInRange"` 84 } `json:"queryParameters"` 85 CreateDate string `json:"-"` 86 UpdateDate string `json:"-"` 87 Used json.RawMessage `json:"used"` 88 } 89 90 // UpdateRatePolicyRequest is used to modify an existing rate policy. 91 UpdateRatePolicyRequest struct { 92 RatePolicyID int `json:"id"` 93 ConfigID int `json:"configId"` 94 ConfigVersion int `json:"configVersion"` 95 JsonPayloadRaw json.RawMessage `json:"-"` 96 } 97 98 // UpdateRatePolicyResponse is returned from a call to UpdateRatePolicy. 99 UpdateRatePolicyResponse struct { 100 ID int `json:"id"` 101 ConfigID int `json:"configId"` 102 ConfigVersion int `json:"configVersion"` 103 MatchType string `json:"matchType"` 104 Type string `json:"type"` 105 Name string `json:"name"` 106 Description string `json:"description"` 107 AverageThreshold int `json:"averageThreshold"` 108 BurstThreshold int `json:"burstThreshold"` 109 BurstWindow int `json:"burstWindow"` 110 ClientIdentifier string `json:"clientIdentifier"` 111 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 112 RequestType string `json:"requestType"` 113 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 114 Path struct { 115 PositiveMatch bool `json:"positiveMatch"` 116 Values []string `json:"values"` 117 } `json:"path"` 118 PathMatchType string `json:"pathMatchType"` 119 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 120 FileExtensions struct { 121 PositiveMatch bool `json:"positiveMatch"` 122 Values []string `json:"values"` 123 } `json:"fileExtensions"` 124 Hosts *RatePoliciesHosts `json:"hosts,omitempty"` 125 Hostnames []string `json:"hostnames"` 126 AdditionalMatchOptions []RatePolicyMatchOption `json:"additionalMatchOptions,omitempty"` 127 Condition *RatePolicyCondition `json:"condition,omitempty"` 128 QueryParameters []struct { 129 Name string `json:"name"` 130 Values []string `json:"values"` 131 PositiveMatch bool `json:"positiveMatch"` 132 ValueInRange bool `json:"valueInRange"` 133 } `json:"queryParameters"` 134 CreateDate string `json:"-"` 135 UpdateDate string `json:"-"` 136 Used json.RawMessage `json:"used"` 137 } 138 139 // RemoveRatePolicyRequest is used to remove a rate policy. 140 RemoveRatePolicyRequest struct { 141 ConfigID int `json:"configId"` 142 ConfigVersion int `json:"configVersion"` 143 RatePolicyID int `json:"ratePolicyId"` 144 } 145 146 // RemoveRatePolicyResponse is returned from a call to RemoveRatePolicy. 147 RemoveRatePolicyResponse struct { 148 ID int `json:"id"` 149 ConfigID int `json:"configId"` 150 ConfigVersion int `json:"configVersion"` 151 MatchType string `json:"matchType"` 152 Type string `json:"type"` 153 Name string `json:"name"` 154 Description string `json:"description"` 155 AverageThreshold int `json:"averageThreshold"` 156 BurstThreshold int `json:"burstThreshold"` 157 BurstWindow int `json:"burstWindow"` 158 ClientIdentifier string `json:"clientIdentifier"` 159 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 160 RequestType string `json:"requestType"` 161 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 162 Path struct { 163 PositiveMatch bool `json:"positiveMatch"` 164 Values []string `json:"values"` 165 } `json:"path"` 166 PathMatchType string `json:"pathMatchType"` 167 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 168 FileExtensions struct { 169 PositiveMatch bool `json:"positiveMatch"` 170 Values []string `json:"values"` 171 } `json:"fileExtensions"` 172 Hosts *RatePoliciesHosts `json:"hosts,omitempty"` 173 Hostnames []string `json:"hostnames"` 174 AdditionalMatchOptions []RatePolicyMatchOption `json:"additionalMatchOptions,omitempty"` 175 Condition *RatePolicyCondition `json:"condition,omitempty"` 176 QueryParameters []struct { 177 Name string `json:"name"` 178 Values []string `json:"values"` 179 PositiveMatch bool `json:"positiveMatch"` 180 ValueInRange bool `json:"valueInRange"` 181 } `json:"queryParameters"` 182 CreateDate string `json:"-"` 183 UpdateDate string `json:"-"` 184 Used json.RawMessage `json:"used"` 185 } 186 187 // GetRatePoliciesRequest is used to retrieve the rate policies for a configuration. 188 GetRatePoliciesRequest struct { 189 ConfigID int `json:"configId"` 190 ConfigVersion int `json:"configVersion"` 191 RatePolicyID int `json:"ratePolicyId"` 192 } 193 194 // GetRatePoliciesResponse is returned from a call to GetRatePolicies. 195 GetRatePoliciesResponse struct { 196 RatePolicies []struct { 197 ID int `json:"id"` 198 ConfigID int `json:"-"` 199 ConfigVersion int `json:"-"` 200 MatchType string `json:"matchType,omitempty"` 201 Type string `json:"type,omitempty"` 202 Name string `json:"name,omitempty"` 203 Description string `json:"description,omitempty"` 204 AverageThreshold int `json:"averageThreshold,omitempty"` 205 BurstThreshold int `json:"burstThreshold,omitempty"` 206 BurstWindow int `json:"burstWindow,omitempty"` 207 ClientIdentifier string `json:"clientIdentifier,omitempty"` 208 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 209 RequestType string `json:"requestType,omitempty"` 210 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 211 Path *RatePolicyPath `json:"path,omitempty"` 212 PathMatchType string `json:"pathMatchType,omitempty"` 213 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 214 FileExtensions *RatePolicyFileExtensions `json:"fileExtensions,omitempty"` 215 Hosts *RatePoliciesHosts `json:"hosts,omitempty"` 216 Hostnames []string `json:"hostnames,omitempty"` 217 AdditionalMatchOptions []RatePolicyMatchOption `json:"additionalMatchOptions,omitempty"` 218 Condition *RatePolicyCondition `json:"condition,omitempty"` 219 QueryParameters *RatePolicyQueryParameters `json:"queryParameters,omitempty"` 220 CreateDate string `json:"-"` 221 UpdateDate string `json:"-"` 222 Used json.RawMessage `json:"used"` 223 SameActionOnIpv bool `json:"sameActionOnIpv"` 224 APISelectors *RatePolicyAPISelectors `json:"apiSelectors,omitempty"` 225 BodyParameters *RatePolicyBodyParameters `json:"bodyParameters,omitempty"` 226 } `json:"ratePolicies,omitempty"` 227 } 228 229 // GetRatePolicyRequest is used to retrieve information about a specific rate policy. 230 GetRatePolicyRequest struct { 231 ConfigID int `json:"configId"` 232 ConfigVersion int `json:"configVersion"` 233 RatePolicyID int `json:"ratePolicyId"` 234 } 235 236 // GetRatePolicyResponse is returned from a call to GetRatePolicy. 237 GetRatePolicyResponse struct { 238 ID int `json:"-"` 239 ConfigID int `json:"-"` 240 ConfigVersion int `json:"-"` 241 MatchType string `json:"matchType,omitempty"` 242 Type string `json:"type,omitempty"` 243 Name string `json:"name,omitempty"` 244 Description string `json:"description,omitempty"` 245 AverageThreshold int `json:"averageThreshold,omitempty"` 246 BurstThreshold int `json:"burstThreshold,omitempty"` 247 BurstWindow int `json:"burstWindow,omitempty"` 248 ClientIdentifier string `json:"clientIdentifier,omitempty"` 249 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 250 RequestType string `json:"requestType,omitempty"` 251 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 252 Path *RatePolicyPath `json:"path,omitempty"` 253 PathMatchType string `json:"pathMatchType,omitempty"` 254 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 255 FileExtensions *RatePolicyFileExtensions `json:"fileExtensions,omitempty"` 256 Hosts *RatePoliciesHosts `json:"hosts,omitempty"` 257 Hostnames []string `json:"hostnames,omitempty"` 258 AdditionalMatchOptions []RatePolicyMatchOption `json:"additionalMatchOptions,omitempty"` 259 Condition *RatePolicyCondition `json:"condition,omitempty"` 260 QueryParameters *RatePolicyQueryParameters `json:"queryParameters,omitempty"` 261 CreateDate string `json:"-"` 262 UpdateDate string `json:"-"` 263 Used bool `json:"-"` 264 } 265 266 // RatePolicyAPISelectors is used as part of a rate policy description. 267 RatePolicyAPISelectors []struct { 268 APIDefinitionID int `json:"apiDefinitionId,omitempty"` 269 DefinedResources *bool `json:"definedResources,omitempty"` 270 ResourceIds []int `json:"resourceIds"` 271 UndefinedResources *bool `json:"undefinedResources,omitempty"` 272 } 273 274 // RatePolicyBodyParameters is used as part of a rate policy description. 275 RatePolicyBodyParameters []struct { 276 Name string `json:"name,omitempty"` 277 Values []string `json:"values,omitempty"` 278 PositiveMatch bool `json:"positiveMatch"` 279 ValueInRange bool `json:"valueInRange"` 280 } 281 282 // RatePolicyPath is used as part of a rate policy description. 283 RatePolicyPath struct { 284 PositiveMatch bool `json:"positiveMatch"` 285 Values []string `json:"values,omitempty"` 286 } 287 288 // RatePolicyFileExtensions is used as part of a rate policy description. 289 RatePolicyFileExtensions struct { 290 PositiveMatch bool `json:"positiveMatch"` 291 Values []string `json:"values,omitempty"` 292 } 293 294 // RatePolicyMatchOption is used as part of a rate policy description. 295 RatePolicyMatchOption struct { 296 PositiveMatch bool `json:"positiveMatch"` 297 Type string `json:"type,omitempty"` 298 Values []string `json:"values,omitempty"` 299 } 300 301 // RatePolicyQueryParameters is used as part of a rate policy description. 302 RatePolicyQueryParameters []struct { 303 Name string `json:"name,omitempty"` 304 Values []string `json:"values,omitempty"` 305 PositiveMatch bool `json:"positiveMatch"` 306 ValueInRange bool `json:"valueInRange"` 307 } 308 309 // RatePoliciesHosts is used as part of a rate policy description. 310 RatePoliciesHosts struct { 311 Values *[]string `json:"values,omitempty"` 312 PositiveMatch *json.RawMessage `json:"positiveMatch,omitempty"` 313 } 314 315 // RatePolicyCondition is used as part of a rate policy description. 316 RatePolicyCondition struct { 317 AtomicConditions []struct { 318 Value *json.RawMessage `json:"value,omitempty"` 319 ClassName string `json:"className"` 320 PositiveMatch bool `json:"positiveMatch"` 321 Name []string `json:"name,omitempty"` 322 NameCase bool `json:"nameCase,omitempty"` 323 NameWildcard bool `json:"nameWildcard,omitempty"` 324 ValueCase bool `json:"valueCase,omitempty"` 325 ValueWildcard bool `json:"valueWildcard,omitempty"` 326 SharedIpHandling string `json:"sharedIpHandling,omitempty"` 327 } `json:"atomicConditions,omitempty"` 328 } 329 ) 330 331 // Validate validates a GetRatePolicyRequest. 332 func (v GetRatePolicyRequest) Validate() error { 333 return validation.Errors{ 334 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 335 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 336 "RatePolicyID": validation.Validate(v.RatePolicyID, validation.Required), 337 }.Filter() 338 } 339 340 // Validate validates a GetRatePoliciesRequest. 341 func (v GetRatePoliciesRequest) Validate() error { 342 return validation.Errors{ 343 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 344 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 345 }.Filter() 346 } 347 348 // Validate validates a CreateRatePolicyRequest. 349 func (v CreateRatePolicyRequest) Validate() error { 350 return validation.Errors{ 351 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 352 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 353 }.Filter() 354 } 355 356 // Validate validates an UpdateRatePolicyRequest. 357 func (v UpdateRatePolicyRequest) Validate() error { 358 return validation.Errors{ 359 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 360 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 361 "RatePolicyID": validation.Validate(v.RatePolicyID, validation.Required), 362 }.Filter() 363 } 364 365 // Validate validates a RemoveRatePolicyRequest. 366 func (v RemoveRatePolicyRequest) Validate() error { 367 return validation.Errors{ 368 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 369 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 370 "RatePolicyID": validation.Validate(v.RatePolicyID, validation.Required), 371 }.Filter() 372 } 373 374 func (p *appsec) GetRatePolicy(ctx context.Context, params GetRatePolicyRequest) (*GetRatePolicyResponse, error) { 375 logger := p.Log(ctx) 376 logger.Debug("GetRatePolicy") 377 378 if err := params.Validate(); err != nil { 379 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 380 } 381 382 uri := fmt.Sprintf( 383 "/appsec/v1/configs/%d/versions/%d/rate-policies/%d", 384 params.ConfigID, 385 params.ConfigVersion, 386 params.RatePolicyID) 387 388 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 389 if err != nil { 390 return nil, fmt.Errorf("failed to create GetRatePolicy request: %w", err) 391 } 392 393 var result GetRatePolicyResponse 394 resp, err := p.Exec(req, &result) 395 if err != nil { 396 return nil, fmt.Errorf("get rate policy request failed: %w", err) 397 } 398 if resp.StatusCode != http.StatusOK { 399 return nil, p.Error(resp) 400 } 401 402 return &result, nil 403 } 404 405 func (p *appsec) GetRatePolicies(ctx context.Context, params GetRatePoliciesRequest) (*GetRatePoliciesResponse, error) { 406 logger := p.Log(ctx) 407 logger.Debug("GetRatePolicies") 408 409 if err := params.Validate(); err != nil { 410 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 411 } 412 413 uri := fmt.Sprintf( 414 "/appsec/v1/configs/%d/versions/%d/rate-policies", 415 params.ConfigID, 416 params.ConfigVersion, 417 ) 418 419 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 420 if err != nil { 421 return nil, fmt.Errorf("failed to create GetRatePolicies request: %w", err) 422 } 423 424 var result GetRatePoliciesResponse 425 resp, err := p.Exec(req, &result) 426 if err != nil { 427 return nil, fmt.Errorf("get rate policies request failed: %w", err) 428 } 429 if resp.StatusCode != http.StatusOK { 430 return nil, p.Error(resp) 431 } 432 433 if params.RatePolicyID != 0 { 434 var filteredResult GetRatePoliciesResponse 435 for _, val := range result.RatePolicies { 436 if val.ID == params.RatePolicyID { 437 filteredResult.RatePolicies = append(filteredResult.RatePolicies, val) 438 } 439 } 440 return &filteredResult, nil 441 } 442 443 return &result, nil 444 } 445 446 func (p *appsec) UpdateRatePolicy(ctx context.Context, params UpdateRatePolicyRequest) (*UpdateRatePolicyResponse, error) { 447 logger := p.Log(ctx) 448 logger.Debug("UpdateRatePolicy") 449 450 if err := params.Validate(); err != nil { 451 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 452 } 453 454 uri := fmt.Sprintf( 455 "/appsec/v1/configs/%d/versions/%d/rate-policies/%d", 456 params.ConfigID, 457 params.ConfigVersion, 458 params.RatePolicyID, 459 ) 460 461 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 462 if err != nil { 463 return nil, fmt.Errorf("failed to create UpdateRatePolicy request: %w", err) 464 } 465 466 var result UpdateRatePolicyResponse 467 req.Header.Set("Content-Type", "application/json") 468 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 469 if err != nil { 470 return nil, fmt.Errorf("update rate policy request failed: %w", err) 471 } 472 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 473 return nil, p.Error(resp) 474 } 475 476 return &result, nil 477 } 478 479 func (p *appsec) CreateRatePolicy(ctx context.Context, params CreateRatePolicyRequest) (*CreateRatePolicyResponse, error) { 480 logger := p.Log(ctx) 481 logger.Debug("CreateRatePolicy") 482 483 if err := params.Validate(); err != nil { 484 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 485 } 486 487 uri := fmt.Sprintf( 488 "/appsec/v1/configs/%d/versions/%d/rate-policies", 489 params.ConfigID, 490 params.ConfigVersion, 491 ) 492 493 req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) 494 if err != nil { 495 return nil, fmt.Errorf("failed to create CreateRatePolicy request: %w", err) 496 } 497 498 var result CreateRatePolicyResponse 499 req.Header.Set("Content-Type", "application/json") 500 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 501 if err != nil { 502 return nil, fmt.Errorf("create rate policy request failed: %w", err) 503 } 504 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 505 return nil, p.Error(resp) 506 } 507 508 return &result, nil 509 } 510 511 func (p *appsec) RemoveRatePolicy(ctx context.Context, params RemoveRatePolicyRequest) (*RemoveRatePolicyResponse, error) { 512 logger := p.Log(ctx) 513 logger.Debug("RemoveRatePolicy") 514 515 if err := params.Validate(); err != nil { 516 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 517 } 518 519 uri := fmt.Sprintf("/appsec/v1/configs/%d/versions/%d/rate-policies/%d", params.ConfigID, params.ConfigVersion, params.RatePolicyID) 520 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) 521 if err != nil { 522 return nil, fmt.Errorf("failed to create RemoveRatePolicy request: %w", err) 523 } 524 525 var result RemoveRatePolicyResponse 526 resp, err := p.Exec(req, &result) 527 if err != nil { 528 return nil, fmt.Errorf("remove rate policy request failed: %w", err) 529 } 530 if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { 531 return nil, p.Error(resp) 532 } 533 534 return &result, nil 535 }