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  }