crowdsec/pkg/cticlient/cti_test.go
Thibault "bui" Koechlin 4f29ce2ee7
CTI API Helpers in expr (#1851)
* Add CTI API helpers in expr
* Allow profiles to have an `on_error` option to profiles

Co-authored-by: Sebastien Blot <sebastien@crowdsec.net>
2023-01-19 08:45:50 +01:00

304 lines
8.8 KiB
Go

package cticlient
// import (
// "encoding/json"
// "net/http"
// "net/http/httptest"
// "net/url"
// "strings"
// "testing"
// "time"
// "github.com/stretchr/testify/assert"
// )
// var sampledata = map[string]CTIResponse{
// //1.2.3.4 is a known false positive
// "1.2.3.4": {
// Ip: "1.2.3.4",
// Classifications: CTIClassifications{
// FalsePositives: []CTIClassification{
// {
// Name: "example_false_positive",
// Label: "Example False Positive",
// },
// },
// },
// },
// //1.2.3.5 is a known bad-guy, and part of FIRE
// "1.2.3.5": {
// Ip: "1.2.3.5",
// Classifications: CTIClassifications{
// Classifications: []CTIClassification{
// {
// Name: "community-blocklist",
// Label: "CrowdSec Community Blocklist",
// Description: "IP belong to the CrowdSec Community Blocklist",
// },
// },
// },
// },
// //1.2.3.6 is a bad guy (high bg noise), but not in FIRE
// "1.2.3.6": {
// Ip: "1.2.3.6",
// BackgroundNoiseScore: new(int),
// Behaviors: []*CTIBehavior{
// {Name: "ssh:bruteforce", Label: "SSH Bruteforce", Description: "SSH Bruteforce"},
// },
// AttackDetails: []*CTIAttackDetails{
// {Name: "crowdsecurity/ssh-bf", Label: "Example Attack"},
// {Name: "crowdsecurity/ssh-slow-bf", Label: "Example Attack"},
// },
// },
// //1.2.3.7 is a ok guy, but part of a bad range
// "1.2.3.7": CTIResponse{},
// }
// func EmptyCTIResponse(ip string) CTIResponse {
// return CTIResponse{
// IpRangeScore: 0,
// Ip: ip,
// Location: CTILocationInfo{},
// }
// }
// /*
// TBD : Simulate correctly quotas exhaustion
// */
// func setup() (Router *http.ServeMux, serverURL string, teardown func()) {
// //set static values
// *sampledata["1.2.3.6"].BackgroundNoiseScore = 10
// // mux is the HTTP request multiplexer used with the test server.
// Router = http.NewServeMux()
// baseURLPath := "/v2"
// apiHandler := http.NewServeMux()
// apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, Router))
// // server is a test HTTP server used to provide mock API responses.
// server := httptest.NewServer(apiHandler)
// // let's mock the API endpoints
// Router.HandleFunc("/smoke/", func(w http.ResponseWriter, r *http.Request) {
// //testMethod(t, r, "GET")
// if r.Header.Get("X-Api-Key") != "EXAMPLE_API_KEY" {
// w.WriteHeader(http.StatusForbidden)
// w.Write([]byte(`{"message":"Forbidden"}`))
// return
// }
// frags := strings.Split(r.RequestURI, "/")
// //[empty] [smoke] [v2] [actual_ip]
// if len(frags) != 4 {
// w.WriteHeader(http.StatusBadRequest)
// w.Write([]byte(`{"message":"Bad Request"}`))
// return
// }
// ip := frags[3]
// if ip == "" {
// //to be fixed to stick w/ real behavior
// panic("empty ip")
// }
// // vars := mux.Vars(r)
// if v, ok := sampledata[ip]; ok {
// data, err := json.Marshal(v)
// if err != nil {
// panic("unable to marshal")
// }
// w.WriteHeader(http.StatusOK)
// w.Write(data)
// return
// }
// w.WriteHeader(http.StatusOK)
// data, err := json.Marshal(EmptyCTIResponse(ip))
// if err != nil {
// panic("unable to marshal")
// }
// w.Write(data)
// return
// })
// return Router, server.URL, server.Close
// }
// func TestCTIAuthKO(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "BAD_KEY"
// if err := InitCTI(&key, nil, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.4")
// assert.Equal(t, false, ret.Ok(), "should be ko")
// assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
// assert.Equal(t, CTIApiEnabled, false, "auth failed, api disabled")
// //auth is disabled, we should always receive empty object
// ret = IpCTI("1.2.3.4")
// assert.Equal(t, false, ret.Ok(), "should be ko")
// assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
// }
// func TestCTINoKey(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// //key := ""
// err = InitCTI(nil, nil, nil)
// assert.NotEqual(t, err, nil, "InitCTI should fail")
// ret := IpCTI("1.2.3.4")
// assert.Equal(t, false, ret.Ok(), "should be ko")
// assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
// assert.Equal(t, CTIApiEnabled, false, "auth failed, api disabled")
// }
// func TestCTIAuthOK(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "EXAMPLE_API_KEY"
// if err := InitCTI(&key, nil, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.4")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.4", ret.Ip, "auth failed, empty answer")
// assert.Equal(t, CTIApiEnabled, true, "auth failed, api disabled")
// }
// func TestCTIKnownFP(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "EXAMPLE_API_KEY"
// if err := InitCTI(&key, nil, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.4")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.4", ret.Ip, "auth failed, empty answer")
// assert.Equal(t, ret.IsFalsePositive(), true, "1.2.3.4 is a known false positive")
// }
// func TestCTIBelongsToFire(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "EXAMPLE_API_KEY"
// if err := InitCTI(&key, nil, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.5")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.5", ret.Ip, "auth failed, empty answer")
// assert.Equal(t, ret.IsPartOfCommunityBlocklist(), true, "1.2.3.5 is a known false positive")
// }
// func TestCTIBehaviors(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "EXAMPLE_API_KEY"
// if err := InitCTI(&key, nil, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.6")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, ret.Ip, "1.2.3.6", "auth failed, empty answer")
// //ssh:bruteforce
// assert.Equal(t, []string{"ssh:bruteforce"}, ret.GetBehaviors(), "error matching behaviors")
// assert.Equal(t, []string{"crowdsecurity/ssh-bf", "crowdsecurity/ssh-slow-bf"}, ret.GetAttackDetails(), "error matching behaviors")
// assert.Equal(t, 10, ret.GetBackgroundNoiseScore(), "error matching bg noise")
// }
// func TestCacheFetch(t *testing.T) {
// _, urlx, teardown := setup()
// apiURL, err := url.Parse(urlx + "/")
// if err != nil {
// t.Fatalf("parsing api url: %s", apiURL)
// }
// defer teardown()
// defer ShutdownCTI()
// CTIUrl = urlx
// key := "EXAMPLE_API_KEY"
// ttl := 1 * time.Second
// if err := InitCTI(&key, &ttl, nil); err != nil {
// t.Fatalf("InitCTI failed: %s", err)
// }
// ret := IpCTI("1.2.3.6")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.6", ret.Ip, "initial fetch : bad item")
// assert.Equal(t, 1, CTICache.Len(true), "initial fetch : bad cache size")
// assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
// //get it a second time before it expires
// ret = IpCTI("1.2.3.6")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.6", ret.Ip, "initial fetch : bad item")
// assert.Equal(t, 1, CTICache.Len(true), "initial fetch : bad cache size")
// assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
// //let data expire
// time.Sleep(1 * time.Second)
// assert.Equal(t, 0, CTICache.Len(true), "after ttl : bad cache size")
// //fetch again
// ret = IpCTI("1.2.3.6")
// assert.Equal(t, true, ret.Ok(), "should be ok")
// assert.Equal(t, "1.2.3.6", ret.Ip, "second fetch : bad item")
// assert.Equal(t, 1, CTICache.Len(true), "second fetch : bad cache size")
// assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
// }
// //GetMaliciousnessScore