github.com/crowdsecurity/crowdsec@v1.6.1/pkg/cticlient/cti_test.go (about)

     1  package cticlient
     2  
     3  // import (
     4  // 	"encoding/json"
     5  // 	"net/http"
     6  // 	"net/http/httptest"
     7  // 	"net/url"
     8  // 	"strings"
     9  // 	"testing"
    10  // 	"time"
    11  
    12  // 	"github.com/stretchr/testify/assert"
    13  // )
    14  
    15  // var sampledata = map[string]CTIResponse{
    16  // 	//1.2.3.4 is a known false positive
    17  // 	"1.2.3.4": {
    18  // 		Ip: "1.2.3.4",
    19  // 		Classifications: CTIClassifications{
    20  // 			FalsePositives: []CTIClassification{
    21  // 				{
    22  // 					Name:  "example_false_positive",
    23  // 					Label: "Example False Positive",
    24  // 				},
    25  // 			},
    26  // 		},
    27  // 	},
    28  // 	//1.2.3.5 is a known bad-guy, and part of FIRE
    29  // 	"1.2.3.5": {
    30  // 		Ip: "1.2.3.5",
    31  // 		Classifications: CTIClassifications{
    32  // 			Classifications: []CTIClassification{
    33  // 				{
    34  // 					Name:        "community-blocklist",
    35  // 					Label:       "CrowdSec Community Blocklist",
    36  // 					Description: "IP belong to the CrowdSec Community Blocklist",
    37  // 				},
    38  // 			},
    39  // 		},
    40  // 	},
    41  // 	//1.2.3.6 is a bad guy (high bg noise), but not in FIRE
    42  // 	"1.2.3.6": {
    43  // 		Ip:                   "1.2.3.6",
    44  // 		BackgroundNoiseScore: new(int),
    45  // 		Behaviors: []*CTIBehavior{
    46  // 			{Name: "ssh:bruteforce", Label: "SSH Bruteforce", Description: "SSH Bruteforce"},
    47  // 		},
    48  // 		AttackDetails: []*CTIAttackDetails{
    49  // 			{Name: "crowdsecurity/ssh-bf", Label: "Example Attack"},
    50  // 			{Name: "crowdsecurity/ssh-slow-bf", Label: "Example Attack"},
    51  // 		},
    52  // 	},
    53  // 	//1.2.3.7 is a ok guy, but part of a bad range
    54  // 	"1.2.3.7": CTIResponse{},
    55  // }
    56  
    57  // func EmptyCTIResponse(ip string) CTIResponse {
    58  // 	return CTIResponse{
    59  // 		IpRangeScore: 0,
    60  // 		Ip:           ip,
    61  // 		Location:     CTILocationInfo{},
    62  // 	}
    63  // }
    64  
    65  // /*
    66  // TBD : Simulate correctly quotas exhaustion
    67  // */
    68  // func setup() (Router *http.ServeMux, serverURL string, teardown func()) {
    69  
    70  // 	//set static values
    71  // 	*sampledata["1.2.3.6"].BackgroundNoiseScore = 10
    72  
    73  // 	// mux is the HTTP request multiplexer used with the test server.
    74  // 	Router = http.NewServeMux()
    75  // 	baseURLPath := "/v2"
    76  
    77  // 	apiHandler := http.NewServeMux()
    78  // 	apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, Router))
    79  
    80  // 	// server is a test HTTP server used to provide mock API responses.
    81  // 	server := httptest.NewServer(apiHandler)
    82  
    83  // 	// let's mock the API endpoints
    84  // 	Router.HandleFunc("/smoke/", func(w http.ResponseWriter, r *http.Request) {
    85  // 		//testMethod(t, r, "GET")
    86  // 		if r.Header.Get("X-Api-Key") != "EXAMPLE_API_KEY" {
    87  // 			w.WriteHeader(http.StatusForbidden)
    88  // 			w.Write([]byte(`{"message":"Forbidden"}`))
    89  // 			return
    90  // 		}
    91  
    92  // 		frags := strings.Split(r.RequestURI, "/")
    93  // 		//[empty] [smoke] [v2] [actual_ip]
    94  // 		if len(frags) != 4 {
    95  // 			w.WriteHeader(http.StatusBadRequest)
    96  // 			w.Write([]byte(`{"message":"Bad Request"}`))
    97  // 			return
    98  // 		}
    99  // 		ip := frags[3]
   100  
   101  // 		if ip == "" {
   102  // 			//to be fixed to stick w/ real behavior
   103  // 			panic("empty ip")
   104  
   105  // 		}
   106  // 		// vars := mux.Vars(r)
   107  // 		if v, ok := sampledata[ip]; ok {
   108  // 			data, err := json.Marshal(v)
   109  // 			if err != nil {
   110  // 				panic("unable to marshal")
   111  // 			}
   112  // 			w.WriteHeader(http.StatusOK)
   113  // 			w.Write(data)
   114  // 			return
   115  // 		}
   116  // 		w.WriteHeader(http.StatusOK)
   117  // 		data, err := json.Marshal(EmptyCTIResponse(ip))
   118  // 		if err != nil {
   119  // 			panic("unable to marshal")
   120  // 		}
   121  // 		w.Write(data)
   122  // 		return
   123  // 	})
   124  // 	return Router, server.URL, server.Close
   125  // }
   126  
   127  // func TestCTIAuthKO(t *testing.T) {
   128  
   129  // 	_, urlx, teardown := setup()
   130  // 	apiURL, err := url.Parse(urlx + "/")
   131  // 	if err != nil {
   132  // 		t.Fatalf("parsing api url: %s", apiURL)
   133  // 	}
   134  
   135  // 	defer teardown()
   136  // 	defer ShutdownCTI()
   137  // 	CTIUrl = urlx
   138  // 	key := "BAD_KEY"
   139  // 	if err := InitCTI(&key, nil, nil); err != nil {
   140  // 		t.Fatalf("InitCTI failed: %s", err)
   141  // 	}
   142  
   143  // 	ret := IpCTI("1.2.3.4")
   144  // 	assert.Equal(t, false, ret.Ok(), "should be ko")
   145  // 	assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
   146  // 	assert.Equal(t, CTIApiEnabled, false, "auth failed, api disabled")
   147  // 	//auth is disabled, we should always receive empty object
   148  // 	ret = IpCTI("1.2.3.4")
   149  // 	assert.Equal(t, false, ret.Ok(), "should be ko")
   150  // 	assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
   151  // }
   152  
   153  // func TestCTINoKey(t *testing.T) {
   154  
   155  // 	_, urlx, teardown := setup()
   156  // 	apiURL, err := url.Parse(urlx + "/")
   157  // 	if err != nil {
   158  // 		t.Fatalf("parsing api url: %s", apiURL)
   159  // 	}
   160  
   161  // 	defer teardown()
   162  // 	defer ShutdownCTI()
   163  // 	CTIUrl = urlx
   164  // 	//key := ""
   165  // 	err = InitCTI(nil, nil, nil)
   166  // 	assert.NotEqual(t, err, nil, "InitCTI should fail")
   167  // 	ret := IpCTI("1.2.3.4")
   168  // 	assert.Equal(t, false, ret.Ok(), "should be ko")
   169  // 	assert.Equal(t, CTIResponse{}, ret, "auth failed, empty answer")
   170  // 	assert.Equal(t, CTIApiEnabled, false, "auth failed, api disabled")
   171  // }
   172  
   173  // func TestCTIAuthOK(t *testing.T) {
   174  
   175  // 	_, urlx, teardown := setup()
   176  // 	apiURL, err := url.Parse(urlx + "/")
   177  // 	if err != nil {
   178  // 		t.Fatalf("parsing api url: %s", apiURL)
   179  // 	}
   180  
   181  // 	defer teardown()
   182  // 	defer ShutdownCTI()
   183  
   184  // 	CTIUrl = urlx
   185  // 	key := "EXAMPLE_API_KEY"
   186  // 	if err := InitCTI(&key, nil, nil); err != nil {
   187  // 		t.Fatalf("InitCTI failed: %s", err)
   188  // 	}
   189  
   190  // 	ret := IpCTI("1.2.3.4")
   191  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   192  // 	assert.Equal(t, "1.2.3.4", ret.Ip, "auth failed, empty answer")
   193  // 	assert.Equal(t, CTIApiEnabled, true, "auth failed, api disabled")
   194  // }
   195  // func TestCTIKnownFP(t *testing.T) {
   196  // 	_, urlx, teardown := setup()
   197  // 	apiURL, err := url.Parse(urlx + "/")
   198  // 	if err != nil {
   199  // 		t.Fatalf("parsing api url: %s", apiURL)
   200  // 	}
   201  
   202  // 	defer teardown()
   203  // 	defer ShutdownCTI()
   204  
   205  // 	CTIUrl = urlx
   206  // 	key := "EXAMPLE_API_KEY"
   207  // 	if err := InitCTI(&key, nil, nil); err != nil {
   208  // 		t.Fatalf("InitCTI failed: %s", err)
   209  // 	}
   210  
   211  // 	ret := IpCTI("1.2.3.4")
   212  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   213  // 	assert.Equal(t, "1.2.3.4", ret.Ip, "auth failed, empty answer")
   214  // 	assert.Equal(t, ret.IsFalsePositive(), true, "1.2.3.4 is a known false positive")
   215  // }
   216  
   217  // func TestCTIBelongsToFire(t *testing.T) {
   218  // 	_, urlx, teardown := setup()
   219  // 	apiURL, err := url.Parse(urlx + "/")
   220  // 	if err != nil {
   221  // 		t.Fatalf("parsing api url: %s", apiURL)
   222  // 	}
   223  
   224  // 	defer teardown()
   225  // 	defer ShutdownCTI()
   226  
   227  // 	CTIUrl = urlx
   228  // 	key := "EXAMPLE_API_KEY"
   229  // 	if err := InitCTI(&key, nil, nil); err != nil {
   230  // 		t.Fatalf("InitCTI failed: %s", err)
   231  // 	}
   232  
   233  // 	ret := IpCTI("1.2.3.5")
   234  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   235  // 	assert.Equal(t, "1.2.3.5", ret.Ip, "auth failed, empty answer")
   236  // 	assert.Equal(t, ret.IsPartOfCommunityBlocklist(), true, "1.2.3.5 is a known false positive")
   237  // }
   238  
   239  // func TestCTIBehaviors(t *testing.T) {
   240  // 	_, urlx, teardown := setup()
   241  // 	apiURL, err := url.Parse(urlx + "/")
   242  // 	if err != nil {
   243  // 		t.Fatalf("parsing api url: %s", apiURL)
   244  // 	}
   245  
   246  // 	defer teardown()
   247  // 	defer ShutdownCTI()
   248  
   249  // 	CTIUrl = urlx
   250  // 	key := "EXAMPLE_API_KEY"
   251  // 	if err := InitCTI(&key, nil, nil); err != nil {
   252  // 		t.Fatalf("InitCTI failed: %s", err)
   253  // 	}
   254  
   255  // 	ret := IpCTI("1.2.3.6")
   256  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   257  // 	assert.Equal(t, ret.Ip, "1.2.3.6", "auth failed, empty answer")
   258  // 	//ssh:bruteforce
   259  // 	assert.Equal(t, []string{"ssh:bruteforce"}, ret.GetBehaviors(), "error matching behaviors")
   260  // 	assert.Equal(t, []string{"crowdsecurity/ssh-bf", "crowdsecurity/ssh-slow-bf"}, ret.GetAttackDetails(), "error matching behaviors")
   261  // 	assert.Equal(t, 10, ret.GetBackgroundNoiseScore(), "error matching bg noise")
   262  // }
   263  
   264  // func TestCacheFetch(t *testing.T) {
   265  // 	_, urlx, teardown := setup()
   266  // 	apiURL, err := url.Parse(urlx + "/")
   267  // 	if err != nil {
   268  // 		t.Fatalf("parsing api url: %s", apiURL)
   269  // 	}
   270  
   271  // 	defer teardown()
   272  // 	defer ShutdownCTI()
   273  
   274  // 	CTIUrl = urlx
   275  // 	key := "EXAMPLE_API_KEY"
   276  // 	ttl := 1 * time.Second
   277  // 	if err := InitCTI(&key, &ttl, nil); err != nil {
   278  // 		t.Fatalf("InitCTI failed: %s", err)
   279  // 	}
   280  
   281  // 	ret := IpCTI("1.2.3.6")
   282  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   283  // 	assert.Equal(t, "1.2.3.6", ret.Ip, "initial fetch : bad item")
   284  // 	assert.Equal(t, 1, CTICache.Len(true), "initial fetch : bad cache size")
   285  // 	assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
   286  // 	//get it a second time before it expires
   287  // 	ret = IpCTI("1.2.3.6")
   288  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   289  // 	assert.Equal(t, "1.2.3.6", ret.Ip, "initial fetch : bad item")
   290  // 	assert.Equal(t, 1, CTICache.Len(true), "initial fetch : bad cache size")
   291  // 	assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
   292  // 	//let data expire
   293  // 	time.Sleep(1 * time.Second)
   294  // 	assert.Equal(t, 0, CTICache.Len(true), "after ttl : bad cache size")
   295  // 	//fetch again
   296  // 	ret = IpCTI("1.2.3.6")
   297  // 	assert.Equal(t, true, ret.Ok(), "should be ok")
   298  // 	assert.Equal(t, "1.2.3.6", ret.Ip, "second fetch : bad item")
   299  // 	assert.Equal(t, 1, CTICache.Len(true), "second fetch : bad cache size")
   300  // 	assert.Equal(t, "1.2.3.6", CTICache.Keys(true)[0].(string), "initial fetch : bad cache keys")
   301  // }
   302  
   303  // //GetMaliciousnessScore