github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/appsec/rule.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 Rule interface supports retrieving and modifying the rules in a policy together with their 14 // actions, conditions and exceptions, or the action, condition and exceptions of a specific rule. 15 Rule interface { 16 // GetRules returns the action taken for each rule in a policy. 17 // 18 // See: https://techdocs.akamai.com/application-security/reference/get-policy-rules 19 GetRules(ctx context.Context, params GetRulesRequest) (*GetRulesResponse, error) 20 21 // GetRule returns the action a rule takes when triggered with conditions and exceptions. 22 // 23 // See: https://techdocs.akamai.com/application-security/reference/get-rule-condition-exception-1 24 // See: https://techdocs.akamai.com/application-security/reference/get-rule-1 25 GetRule(ctx context.Context, params GetRuleRequest) (*GetRuleResponse, error) 26 27 // UpdateRule updates what action a rule takes when it's triggered. 28 // 29 // See: https://techdocs.akamai.com/application-security/reference/put-rule-1 30 UpdateRule(ctx context.Context, params UpdateRuleRequest) (*UpdateRuleResponse, error) 31 32 // UpdateRuleConditionException updates a rule's conditions and exceptions. 33 // 34 // See: https://techdocs.akamai.com/application-security/reference/put-rule-condition-exception-1 35 UpdateRuleConditionException(ctx context.Context, params UpdateConditionExceptionRequest) (*UpdateConditionExceptionResponse, error) 36 } 37 38 // GetRulesRequest is used to retrieve the rules for a configuration and policy, together with their actions and condition and exception information. 39 GetRulesRequest struct { 40 ConfigID int `json:"-"` 41 Version int `json:"-"` 42 PolicyID string `json:"-"` 43 RuleID int `json:"-"` 44 } 45 46 // GetRulesResponse is returned from a call to GetRules. 47 GetRulesResponse struct { 48 Rules []struct { 49 ID int `json:"id,omitempty"` 50 Action string `json:"action,omitempty"` 51 ConditionException *RuleConditionException `json:"conditionException,omitempty"` 52 } `json:"ruleActions,omitempty"` 53 } 54 55 // GetRuleRequest is used to retrieve a rule together with its action and its condition and exception information. 56 GetRuleRequest struct { 57 ConfigID int `json:"-"` 58 Version int `json:"-"` 59 PolicyID string `json:"-"` 60 RuleID int `json:"-"` 61 } 62 63 // GetRuleResponse is returned from a call to GetRule. 64 GetRuleResponse struct { 65 Action string `json:"action,omitempty"` 66 ConditionException *RuleConditionException `json:"conditionException,omitempty"` 67 } 68 69 // UpdateRuleRequest is used to modify the settings for a rule. 70 UpdateRuleRequest struct { 71 ConfigID int `json:"-"` 72 Version int `json:"-"` 73 PolicyID string `json:"-"` 74 RuleID int `json:"-"` 75 Action string `json:"action"` 76 JsonPayloadRaw json.RawMessage `json:"conditionException,omitempty"` 77 } 78 79 // UpdateRuleResponse is returned from a call to UpdateRule. 80 UpdateRuleResponse struct { 81 Action string `json:"action,omitempty"` 82 ConditionException *RuleConditionException `json:"conditionException,omitempty"` 83 } 84 85 // AdvancedExceptions is used to describe advanced exceptions used in Adaptive Security Engine(ASE) rules. 86 AdvancedExceptions AttackGroupAdvancedExceptions 87 88 // RuleConditionException is used to describe the conditions and exceptions for a rule. 89 RuleConditionException struct { 90 Conditions *RuleConditions `json:"conditions,omitempty"` 91 Exception *RuleException `json:"exception,omitempty"` 92 AdvancedExceptionsList *AdvancedExceptions `json:"advancedExceptions,omitempty"` 93 } 94 95 // RuleConditions is used to describe the conditions for a rule. 96 RuleConditions []struct { 97 Type string `json:"type,omitempty"` 98 Extensions []string `json:"extensions,omitempty"` 99 Filenames []string `json:"filenames,omitempty"` 100 Hosts []string `json:"hosts,omitempty"` 101 Ips []string `json:"ips,omitempty"` 102 Methods []string `json:"methods,omitempty"` 103 Paths []string `json:"paths,omitempty"` 104 Header string `json:"header,omitempty"` 105 CaseSensitive bool `json:"caseSensitive,omitempty"` 106 Name string `json:"name,omitempty"` 107 NameCase bool `json:"nameCase,omitempty"` 108 PositiveMatch bool `json:"positiveMatch"` 109 Value string `json:"value,omitempty"` 110 Wildcard bool `json:"wildcard,omitempty"` 111 ValueCase bool `json:"valueCase,omitempty"` 112 ValueWildcard bool `json:"valueWildcard,omitempty"` 113 UseHeaders bool `json:"useHeaders,omitempty"` 114 } 115 116 // RuleException is used to describe the exceptions for a rule. 117 RuleException struct { 118 AnyHeaderCookieOrParam []string `json:"anyHeaderCookieOrParam,omitempty"` 119 HeaderCookieOrParamValues []string `json:"headerCookieOrParamValues,omitempty"` 120 SpecificHeaderCookieOrParamNameValue *SpecificHeaderCookieOrParamNameValuePtr `json:"specificHeaderCookieOrParamNameValue,omitempty"` 121 SpecificHeaderCookieOrParamNames *SpecificHeaderCookieOrParamNamesPtr `json:"specificHeaderCookieOrParamNames,omitempty"` 122 SpecificHeaderCookieOrParamPrefix *SpecificHeaderCookieOrParamPrefixPtr `json:"specificHeaderCookieOrParamPrefix,omitempty"` 123 SpecificHeaderCookieParamXMLOrJSONNames *SpecificHeaderCookieParamXMLOrJSONNames `json:"specificHeaderCookieParamXmlOrJsonNames,omitempty"` 124 } 125 126 // SpecificHeaderCookieOrParamNamesPtr is used as part of condition and exception information for a rule. 127 SpecificHeaderCookieOrParamNamesPtr []struct { 128 Names []string `json:"names,omitempty"` 129 Selector string `json:"selector,omitempty"` 130 } 131 132 // SpecificHeaderCookieOrParamPrefixPtr is used as part of condition and exception information for a rule. 133 SpecificHeaderCookieOrParamPrefixPtr struct { 134 Prefix string `json:"prefix,omitempty"` 135 Selector string `json:"selector,omitempty"` 136 } 137 138 // SpecificHeaderCookieOrParamNameValuePtr is used as part of condition and exception information for a rule. 139 SpecificHeaderCookieOrParamNameValuePtr struct { 140 Name string `json:"name,omitempty"` 141 Selector string `json:"selector,omitempty"` 142 Value string `json:"value,omitempty"` 143 } 144 145 // SpecificHeaderCookieParamXMLOrJSONNames is used as part of condition and exception information for an ASE rule. 146 SpecificHeaderCookieParamXMLOrJSONNames AttackGroupSpecificHeaderCookieParamXMLOrJSONNames 147 148 // UpdateConditionExceptionRequest is used to update the condition and exception information for a rule. 149 UpdateConditionExceptionRequest struct { 150 ConfigID int `json:"-"` 151 Version int `json:"-"` 152 PolicyID string `json:"-"` 153 RuleID int `json:"-"` 154 Conditions *RuleConditions `json:"conditions,omitempty"` 155 Exception *RuleException `json:"exception,omitempty"` 156 AdvancedExceptionsList *AdvancedExceptions `json:"advancedExceptions,omitempty"` 157 } 158 159 // UpdateConditionExceptionResponse is returned from a call to UpdateConditionException. 160 UpdateConditionExceptionResponse RuleConditionException 161 ) 162 163 // IsEmptyConditionException checks whether a rule's condition and exception information is empty. 164 func (r *GetRuleResponse) IsEmptyConditionException() bool { 165 return r.ConditionException == nil 166 } 167 168 // Validate validates a GetRuleRequest. 169 func (v GetRuleRequest) 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 "RuleID": validation.Validate(v.RuleID, validation.Required), 175 }.Filter() 176 } 177 178 // Validate validates a GetRulesRequest. 179 func (v GetRulesRequest) Validate() error { 180 return validation.Errors{ 181 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 182 "Version": validation.Validate(v.Version, validation.Required), 183 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 184 }.Filter() 185 } 186 187 // Validate validates an UpdateRuleRequest. 188 func (v UpdateRuleRequest) Validate() error { 189 return validation.Errors{ 190 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 191 "Version": validation.Validate(v.Version, validation.Required), 192 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 193 "RuleID": validation.Validate(v.RuleID, validation.Required), 194 }.Filter() 195 } 196 197 // Validate validates an UpdateConditionExceptionRequest. 198 func (v UpdateConditionExceptionRequest) Validate() error { 199 return validation.Errors{ 200 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 201 "Version": validation.Validate(v.Version, validation.Required), 202 "PolicyID": validation.Validate(v.PolicyID, validation.Required), 203 "RuleID": validation.Validate(v.RuleID, validation.Required), 204 }.Filter() 205 } 206 207 func (p *appsec) GetRule(ctx context.Context, params GetRuleRequest) (*GetRuleResponse, error) { 208 logger := p.Log(ctx) 209 logger.Debug("GetRule") 210 211 if err := params.Validate(); err != nil { 212 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 213 } 214 215 uri := fmt.Sprintf( 216 "/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d?includeConditionException=true", 217 params.ConfigID, 218 params.Version, 219 params.PolicyID, 220 params.RuleID) 221 222 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 223 if err != nil { 224 return nil, fmt.Errorf("failed to create GetRule request: %w", err) 225 } 226 227 var result GetRuleResponse 228 resp, err := p.Exec(req, &result) 229 if err != nil { 230 return nil, fmt.Errorf("get rule request failed: %w", err) 231 } 232 if resp.StatusCode != http.StatusOK { 233 return nil, p.Error(resp) 234 } 235 236 return &result, nil 237 } 238 239 func (p *appsec) GetRules(ctx context.Context, params GetRulesRequest) (*GetRulesResponse, error) { 240 logger := p.Log(ctx) 241 logger.Debug("GetRules") 242 243 if err := params.Validate(); err != nil { 244 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 245 } 246 247 uri := fmt.Sprintf( 248 "/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules?includeConditionException=true", 249 params.ConfigID, 250 params.Version, 251 params.PolicyID) 252 253 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 254 if err != nil { 255 return nil, fmt.Errorf("failed to create GetRules request: %w", err) 256 } 257 258 var result GetRulesResponse 259 resp, err := p.Exec(req, &result) 260 if err != nil { 261 return nil, fmt.Errorf("get rules request failed: %w", err) 262 } 263 if resp.StatusCode != http.StatusOK { 264 return nil, p.Error(resp) 265 } 266 267 if params.RuleID != 0 { 268 var filteredResult GetRulesResponse 269 for _, val := range result.Rules { 270 if val.ID == params.RuleID { 271 filteredResult.Rules = append(filteredResult.Rules, val) 272 } 273 } 274 return &filteredResult, nil 275 } 276 277 return &result, nil 278 } 279 280 func (p *appsec) UpdateRule(ctx context.Context, params UpdateRuleRequest) (*UpdateRuleResponse, error) { 281 logger := p.Log(ctx) 282 logger.Debug("UpdateRule") 283 284 if err := params.Validate(); err != nil { 285 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 286 } 287 288 uri := fmt.Sprintf( 289 "/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d/action-condition-exception", 290 params.ConfigID, 291 params.Version, 292 params.PolicyID, 293 params.RuleID, 294 ) 295 296 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 297 if err != nil { 298 return nil, fmt.Errorf("failed to create UpdateRule request: %w", err) 299 } 300 301 var result UpdateRuleResponse 302 resp, err := p.Exec(req, &result, params) 303 if err != nil { 304 return nil, fmt.Errorf("update rule request failed: %w", err) 305 } 306 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 307 return nil, p.Error(resp) 308 } 309 310 return &result, nil 311 } 312 313 func (p *appsec) UpdateRuleConditionException(ctx context.Context, params UpdateConditionExceptionRequest) (*UpdateConditionExceptionResponse, error) { 314 logger := p.Log(ctx) 315 logger.Debug("UpdateRuleConditionException") 316 317 if err := params.Validate(); err != nil { 318 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 319 } 320 321 uri := fmt.Sprintf( 322 "/appsec/v1/configs/%d/versions/%d/security-policies/%s/rules/%d/condition-exception", 323 params.ConfigID, 324 params.Version, 325 params.PolicyID, 326 params.RuleID, 327 ) 328 329 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 330 if err != nil { 331 return nil, fmt.Errorf("failed to create UpdateRuleConditionException request: %w", err) 332 } 333 334 var result UpdateConditionExceptionResponse 335 resp, err := p.Exec(req, &result, params) 336 if err != nil { 337 return nil, fmt.Errorf("update rule condition exception request failed: %w", err) 338 } 339 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 340 return nil, p.Error(resp) 341 } 342 343 return &result, nil 344 }