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