github.com/crowdsecurity/crowdsec@v1.6.1/pkg/apiserver/decisions_test.go (about) 1 package apiserver 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 ) 8 9 const ( 10 APIKEY = "apikey" 11 PASSWORD = "password" 12 ) 13 14 func TestDeleteDecisionRange(t *testing.T) { 15 lapi := SetupLAPITest(t) 16 17 // Create Valid Alert 18 lapi.InsertAlertFromFile(t, "./tests/alert_minibulk.json") 19 20 // delete by ip wrong 21 w := lapi.RecordResponse(t, "DELETE", "/v1/decisions?range=1.2.3.0/24", emptyBody, PASSWORD) 22 assert.Equal(t, 200, w.Code) 23 assert.Equal(t, `{"nbDeleted":"0"}`, w.Body.String()) 24 25 // delete by range 26 27 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions?range=91.121.79.0/24&contains=false", emptyBody, PASSWORD) 28 assert.Equal(t, 200, w.Code) 29 assert.Equal(t, `{"nbDeleted":"2"}`, w.Body.String()) 30 31 // delete by range : ensure it was already deleted 32 33 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions?range=91.121.79.0/24", emptyBody, PASSWORD) 34 assert.Equal(t, 200, w.Code) 35 assert.Equal(t, `{"nbDeleted":"0"}`, w.Body.String()) 36 } 37 38 func TestDeleteDecisionFilter(t *testing.T) { 39 lapi := SetupLAPITest(t) 40 41 // Create Valid Alert 42 lapi.InsertAlertFromFile(t, "./tests/alert_minibulk.json") 43 44 // delete by ip wrong 45 46 w := lapi.RecordResponse(t, "DELETE", "/v1/decisions?ip=1.2.3.4", emptyBody, PASSWORD) 47 assert.Equal(t, 200, w.Code) 48 assert.Equal(t, `{"nbDeleted":"0"}`, w.Body.String()) 49 50 // delete by ip good 51 52 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions?ip=91.121.79.179", emptyBody, PASSWORD) 53 assert.Equal(t, 200, w.Code) 54 assert.Equal(t, `{"nbDeleted":"1"}`, w.Body.String()) 55 56 // delete by scope/value 57 58 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions?scopes=Ip&value=91.121.79.178", emptyBody, PASSWORD) 59 assert.Equal(t, 200, w.Code) 60 assert.Equal(t, `{"nbDeleted":"1"}`, w.Body.String()) 61 } 62 63 func TestDeleteDecisionFilterByScenario(t *testing.T) { 64 lapi := SetupLAPITest(t) 65 66 // Create Valid Alert 67 lapi.InsertAlertFromFile(t, "./tests/alert_minibulk.json") 68 69 // delete by wrong scenario 70 71 w := lapi.RecordResponse(t, "DELETE", "/v1/decisions?scenario=crowdsecurity/ssh-bff", emptyBody, PASSWORD) 72 assert.Equal(t, 200, w.Code) 73 assert.Equal(t, `{"nbDeleted":"0"}`, w.Body.String()) 74 75 // delete by scenario good 76 77 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions?scenario=crowdsecurity/ssh-bf", emptyBody, PASSWORD) 78 assert.Equal(t, 200, w.Code) 79 assert.Equal(t, `{"nbDeleted":"2"}`, w.Body.String()) 80 } 81 82 func TestGetDecisionFilters(t *testing.T) { 83 lapi := SetupLAPITest(t) 84 85 // Create Valid Alert 86 lapi.InsertAlertFromFile(t, "./tests/alert_minibulk.json") 87 88 // Get Decision 89 90 w := lapi.RecordResponse(t, "GET", "/v1/decisions", emptyBody, APIKEY) 91 assert.Equal(t, 200, w.Code) 92 decisions, code := readDecisionsGetResp(t, w) 93 assert.Equal(t, 200, code) 94 assert.Len(t, decisions, 2) 95 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[0].Scenario) 96 assert.Equal(t, "91.121.79.179", *decisions[0].Value) 97 assert.Equal(t, int64(1), decisions[0].ID) 98 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[1].Scenario) 99 assert.Equal(t, "91.121.79.178", *decisions[1].Value) 100 assert.Equal(t, int64(2), decisions[1].ID) 101 102 // Get Decision : type filter 103 104 w = lapi.RecordResponse(t, "GET", "/v1/decisions?type=ban", emptyBody, APIKEY) 105 assert.Equal(t, 200, w.Code) 106 decisions, code = readDecisionsGetResp(t, w) 107 assert.Equal(t, 200, code) 108 assert.Len(t, decisions, 2) 109 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[0].Scenario) 110 assert.Equal(t, "91.121.79.179", *decisions[0].Value) 111 assert.Equal(t, int64(1), decisions[0].ID) 112 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[1].Scenario) 113 assert.Equal(t, "91.121.79.178", *decisions[1].Value) 114 assert.Equal(t, int64(2), decisions[1].ID) 115 116 // assert.Contains(t, w.Body.String(), `"id":1,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.179"`) 117 // assert.Contains(t, w.Body.String(), `"id":2,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.178"`) 118 119 // Get Decision : scope/value 120 121 w = lapi.RecordResponse(t, "GET", "/v1/decisions?scopes=Ip&value=91.121.79.179", emptyBody, APIKEY) 122 assert.Equal(t, 200, w.Code) 123 decisions, code = readDecisionsGetResp(t, w) 124 assert.Equal(t, 200, code) 125 assert.Len(t, decisions, 1) 126 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[0].Scenario) 127 assert.Equal(t, "91.121.79.179", *decisions[0].Value) 128 assert.Equal(t, int64(1), decisions[0].ID) 129 130 // assert.Contains(t, w.Body.String(), `"id":1,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.179"`) 131 // assert.NotContains(t, w.Body.String(), `"id":2,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.178"`) 132 133 // Get Decision : ip filter 134 135 w = lapi.RecordResponse(t, "GET", "/v1/decisions?ip=91.121.79.179", emptyBody, APIKEY) 136 assert.Equal(t, 200, w.Code) 137 decisions, code = readDecisionsGetResp(t, w) 138 assert.Equal(t, 200, code) 139 assert.Len(t, decisions, 1) 140 assert.Equal(t, "crowdsecurity/ssh-bf", *decisions[0].Scenario) 141 assert.Equal(t, "91.121.79.179", *decisions[0].Value) 142 assert.Equal(t, int64(1), decisions[0].ID) 143 144 // assert.Contains(t, w.Body.String(), `"id":1,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.179"`) 145 // assert.NotContains(t, w.Body.String(), `"id":2,"origin":"crowdsec","scenario":"crowdsecurity/ssh-bf","scope":"Ip","type":"ban","value":"91.121.79.178"`) 146 147 // Get decision : by range 148 w = lapi.RecordResponse(t, "GET", "/v1/decisions?range=91.121.79.0/24&contains=false", emptyBody, APIKEY) 149 assert.Equal(t, 200, w.Code) 150 decisions, code = readDecisionsGetResp(t, w) 151 assert.Equal(t, 200, code) 152 assert.Len(t, decisions, 2) 153 assert.Contains(t, []string{*decisions[0].Value, *decisions[1].Value}, "91.121.79.179") 154 assert.Contains(t, []string{*decisions[0].Value, *decisions[1].Value}, "91.121.79.178") 155 } 156 157 func TestGetDecision(t *testing.T) { 158 lapi := SetupLAPITest(t) 159 160 // Create Valid Alert 161 lapi.InsertAlertFromFile(t, "./tests/alert_sample.json") 162 163 // Get Decision 164 w := lapi.RecordResponse(t, "GET", "/v1/decisions", emptyBody, APIKEY) 165 assert.Equal(t, 200, w.Code) 166 decisions, code := readDecisionsGetResp(t, w) 167 assert.Equal(t, 200, code) 168 assert.Len(t, decisions, 3) 169 /*decisions get doesn't perform deduplication*/ 170 assert.Equal(t, "crowdsecurity/test", *decisions[0].Scenario) 171 assert.Equal(t, "127.0.0.1", *decisions[0].Value) 172 assert.Equal(t, int64(1), decisions[0].ID) 173 174 assert.Equal(t, "crowdsecurity/test", *decisions[1].Scenario) 175 assert.Equal(t, "127.0.0.1", *decisions[1].Value) 176 assert.Equal(t, int64(2), decisions[1].ID) 177 178 assert.Equal(t, "crowdsecurity/test", *decisions[2].Scenario) 179 assert.Equal(t, "127.0.0.1", *decisions[2].Value) 180 assert.Equal(t, int64(3), decisions[2].ID) 181 182 // Get Decision with invalid filter. It should ignore this filter 183 w = lapi.RecordResponse(t, "GET", "/v1/decisions?test=test", emptyBody, APIKEY) 184 assert.Equal(t, 200, w.Code) 185 assert.Len(t, decisions, 3) 186 } 187 188 func TestDeleteDecisionByID(t *testing.T) { 189 lapi := SetupLAPITest(t) 190 191 // Create Valid Alert 192 lapi.InsertAlertFromFile(t, "./tests/alert_sample.json") 193 194 //Have one alerts 195 w := lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 196 decisions, code := readDecisionsStreamResp(t, w) 197 assert.Equal(t, 200, code) 198 assert.Empty(t, decisions["deleted"]) 199 assert.Len(t, decisions["new"], 1) 200 201 // Delete alert with Invalid ID 202 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/test", emptyBody, PASSWORD) 203 assert.Equal(t, 400, w.Code) 204 errResp, _ := readDecisionsErrorResp(t, w) 205 assert.Equal(t, "decision_id must be valid integer", errResp["message"]) 206 207 // Delete alert with ID that not exist 208 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/100", emptyBody, PASSWORD) 209 assert.Equal(t, 500, w.Code) 210 errResp, _ = readDecisionsErrorResp(t, w) 211 assert.Equal(t, "decision with id '100' doesn't exist: unable to delete", errResp["message"]) 212 213 //Have one alerts 214 w = lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 215 decisions, code = readDecisionsStreamResp(t, w) 216 assert.Equal(t, 200, code) 217 assert.Empty(t, decisions["deleted"]) 218 assert.Len(t, decisions["new"], 1) 219 220 // Delete alert with valid ID 221 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/1", emptyBody, PASSWORD) 222 assert.Equal(t, 200, w.Code) 223 resp, _ := readDecisionsDeleteResp(t, w) 224 assert.Equal(t, "1", resp.NbDeleted) 225 226 //Have one alert (because we delete an alert that has dup targets) 227 w = lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 228 decisions, code = readDecisionsStreamResp(t, w) 229 assert.Equal(t, 200, code) 230 assert.Empty(t, decisions["deleted"]) 231 assert.Len(t, decisions["new"], 1) 232 } 233 234 func TestDeleteDecision(t *testing.T) { 235 lapi := SetupLAPITest(t) 236 237 // Create Valid Alert 238 lapi.InsertAlertFromFile(t, "./tests/alert_sample.json") 239 240 // Delete alert with Invalid filter 241 w := lapi.RecordResponse(t, "DELETE", "/v1/decisions?test=test", emptyBody, PASSWORD) 242 assert.Equal(t, 500, w.Code) 243 errResp, _ := readDecisionsErrorResp(t, w) 244 assert.Equal(t, "'test' doesn't exist: invalid filter", errResp["message"]) 245 246 // Delete all alert 247 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions", emptyBody, PASSWORD) 248 assert.Equal(t, 200, w.Code) 249 resp, _ := readDecisionsDeleteResp(t, w) 250 assert.Equal(t, "3", resp.NbDeleted) 251 } 252 253 func TestStreamStartDecisionDedup(t *testing.T) { 254 //Ensure that at stream startup we only get the longest decision 255 lapi := SetupLAPITest(t) 256 257 // Create Valid Alert : 3 decisions for 127.0.0.1, longest has id=3 258 lapi.InsertAlertFromFile(t, "./tests/alert_sample.json") 259 260 // Get Stream, we only get one decision (the longest one) 261 w := lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 262 decisions, code := readDecisionsStreamResp(t, w) 263 assert.Equal(t, 200, code) 264 assert.Empty(t, decisions["deleted"]) 265 assert.Len(t, decisions["new"], 1) 266 assert.Equal(t, int64(3), decisions["new"][0].ID) 267 assert.Equal(t, "test", *decisions["new"][0].Origin) 268 assert.Equal(t, "127.0.0.1", *decisions["new"][0].Value) 269 270 // id=3 decision is deleted, this won't affect `deleted`, because there are decisions on the same ip 271 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/3", emptyBody, PASSWORD) 272 assert.Equal(t, 200, w.Code) 273 274 // Get Stream, we only get one decision (the longest one, id=2) 275 w = lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 276 decisions, code = readDecisionsStreamResp(t, w) 277 assert.Equal(t, 200, code) 278 assert.Empty(t, decisions["deleted"]) 279 assert.Len(t, decisions["new"], 1) 280 assert.Equal(t, int64(2), decisions["new"][0].ID) 281 assert.Equal(t, "test", *decisions["new"][0].Origin) 282 assert.Equal(t, "127.0.0.1", *decisions["new"][0].Value) 283 284 // We delete another decision, yet don't receive it in stream, since there's another decision on same IP 285 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/2", emptyBody, PASSWORD) 286 assert.Equal(t, 200, w.Code) 287 288 // And get the remaining decision (1) 289 w = lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 290 decisions, code = readDecisionsStreamResp(t, w) 291 assert.Equal(t, 200, code) 292 assert.Empty(t, decisions["deleted"]) 293 assert.Len(t, decisions["new"], 1) 294 assert.Equal(t, int64(1), decisions["new"][0].ID) 295 assert.Equal(t, "test", *decisions["new"][0].Origin) 296 assert.Equal(t, "127.0.0.1", *decisions["new"][0].Value) 297 298 // We delete the last decision, we receive the delete order 299 w = lapi.RecordResponse(t, "DELETE", "/v1/decisions/1", emptyBody, PASSWORD) 300 assert.Equal(t, 200, w.Code) 301 302 //and now we only get a deleted decision 303 w = lapi.RecordResponse(t, "GET", "/v1/decisions/stream?startup=true", emptyBody, APIKEY) 304 decisions, code = readDecisionsStreamResp(t, w) 305 assert.Equal(t, 200, code) 306 assert.Len(t, decisions["deleted"], 1) 307 assert.Equal(t, int64(1), decisions["deleted"][0].ID) 308 assert.Equal(t, "test", *decisions["deleted"][0].Origin) 309 assert.Equal(t, "127.0.0.1", *decisions["deleted"][0].Value) 310 assert.Empty(t, decisions["new"]) 311 } 312 313 type DecisionCheck struct { 314 ID int64 315 Origin string 316 Scenario string 317 Value string 318 Duration string 319 Type string 320 } 321 322 type DecisionTest struct { 323 TestName string 324 Method string 325 Route string 326 CheckCodeOnly bool 327 Code int 328 LenNew int 329 LenDeleted int 330 NewChecks []DecisionCheck 331 DelChecks []DecisionCheck 332 AuthType string 333 }