apiserver_test.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package apiserver
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "net/http/httptest"
  8. "os"
  9. "strings"
  10. "testing"
  11. "time"
  12. middlewares "github.com/crowdsecurity/crowdsec/pkg/apiserver/middlewares/v1"
  13. "github.com/crowdsecurity/crowdsec/pkg/cwversion"
  14. "github.com/crowdsecurity/crowdsec/pkg/models"
  15. "github.com/crowdsecurity/crowdsec/pkg/types"
  16. "github.com/go-openapi/strfmt"
  17. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  18. "github.com/crowdsecurity/crowdsec/pkg/database"
  19. "github.com/gin-gonic/gin"
  20. log "github.com/sirupsen/logrus"
  21. "github.com/stretchr/testify/assert"
  22. )
  23. var testMachineID = "test"
  24. var testPassword = strfmt.Password("test")
  25. var MachineTest = models.WatcherAuthRequest{
  26. MachineID: &testMachineID,
  27. Password: &testPassword,
  28. }
  29. var UserAgent = fmt.Sprintf("crowdsec-test/%s", cwversion.Version)
  30. func LoadTestConfig() csconfig.Config {
  31. config := csconfig.Config{}
  32. maxAge := "1h"
  33. flushConfig := csconfig.FlushDBCfg{
  34. MaxAge: &maxAge,
  35. }
  36. dbconfig := csconfig.DatabaseCfg{
  37. Type: "sqlite",
  38. DbPath: "./ent",
  39. Flush: &flushConfig,
  40. }
  41. apiServerConfig := csconfig.LocalApiServerCfg{
  42. ListenURI: "http://127.0.0.1:8080",
  43. DbConfig: &dbconfig,
  44. ProfilesPath: "./tests/profiles.yaml",
  45. }
  46. apiConfig := csconfig.APICfg{
  47. Server: &apiServerConfig,
  48. }
  49. config.API = &apiConfig
  50. if err := config.API.Server.LoadProfiles(); err != nil {
  51. log.Fatalf("failed to load profiles: %s", err)
  52. }
  53. return config
  54. }
  55. func LoadTestConfigForwardedFor() csconfig.Config {
  56. config := csconfig.Config{}
  57. maxAge := "1h"
  58. flushConfig := csconfig.FlushDBCfg{
  59. MaxAge: &maxAge,
  60. }
  61. dbconfig := csconfig.DatabaseCfg{
  62. Type: "sqlite",
  63. DbPath: "./ent",
  64. Flush: &flushConfig,
  65. }
  66. apiServerConfig := csconfig.LocalApiServerCfg{
  67. ListenURI: "http://127.0.0.1:8080",
  68. DbConfig: &dbconfig,
  69. ProfilesPath: "./tests/profiles.yaml",
  70. UseForwardedForHeaders: true,
  71. }
  72. apiConfig := csconfig.APICfg{
  73. Server: &apiServerConfig,
  74. }
  75. config.API = &apiConfig
  76. if err := config.API.Server.LoadProfiles(); err != nil {
  77. log.Fatalf("failed to load profiles: %s", err)
  78. }
  79. return config
  80. }
  81. func NewAPITest() (*gin.Engine, error) {
  82. config := LoadTestConfig()
  83. os.Remove("./ent")
  84. apiServer, err := NewServer(config.API.Server)
  85. if err != nil {
  86. return nil, fmt.Errorf("unable to run local API: %s", err)
  87. }
  88. log.Printf("Creating new API server")
  89. gin.SetMode(gin.TestMode)
  90. router, err := apiServer.Router()
  91. if err != nil {
  92. return nil, fmt.Errorf("unable to run local API: %s", err)
  93. }
  94. return router, nil
  95. }
  96. func NewAPITestForwardedFor() (*gin.Engine, error) {
  97. config := LoadTestConfigForwardedFor()
  98. os.Remove("./ent")
  99. apiServer, err := NewServer(config.API.Server)
  100. if err != nil {
  101. return nil, fmt.Errorf("unable to run local API: %s", err)
  102. }
  103. log.Printf("Creating new API server")
  104. gin.SetMode(gin.TestMode)
  105. router, err := apiServer.Router()
  106. if err != nil {
  107. return nil, fmt.Errorf("unable to run local API: %s", err)
  108. }
  109. return router, nil
  110. }
  111. func ValidateMachine(machineID string) error {
  112. config := LoadTestConfig()
  113. dbClient, err := database.NewClient(config.API.Server.DbConfig)
  114. if err != nil {
  115. return fmt.Errorf("unable to create new database client: %s", err)
  116. }
  117. if err := dbClient.ValidateMachine(machineID); err != nil {
  118. return fmt.Errorf("unable to validate machine: %s", err)
  119. }
  120. return nil
  121. }
  122. func GetMachineIP(machineID string) (string, error) {
  123. config := LoadTestConfig()
  124. dbClient, err := database.NewClient(config.API.Server.DbConfig)
  125. if err != nil {
  126. return "", fmt.Errorf("unable to create new database client: %s", err)
  127. }
  128. machines, err := dbClient.ListMachines()
  129. if err != nil {
  130. return "", fmt.Errorf("Unable to list machines: %s", err)
  131. }
  132. for _, machine := range machines {
  133. if machine.MachineId == machineID {
  134. return machine.IpAddress, nil
  135. }
  136. }
  137. return "", nil
  138. }
  139. func CreateTestMachine(router *gin.Engine) (string, error) {
  140. b, err := json.Marshal(MachineTest)
  141. if err != nil {
  142. return "", fmt.Errorf("unable to marshal MachineTest")
  143. }
  144. body := string(b)
  145. w := httptest.NewRecorder()
  146. req, _ := http.NewRequest("POST", "/v1/watchers", strings.NewReader(body))
  147. req.Header.Set("User-Agent", UserAgent)
  148. router.ServeHTTP(w, req)
  149. return body, nil
  150. }
  151. func CreateTestBouncer() (string, error) {
  152. config := LoadTestConfig()
  153. dbClient, err := database.NewClient(config.API.Server.DbConfig)
  154. if err != nil {
  155. log.Fatalf("unable to create new database client: %s", err)
  156. }
  157. apiKey, err := middlewares.GenerateAPIKey(keyLength)
  158. if err != nil {
  159. return "", fmt.Errorf("unable to generate api key: %s", err)
  160. }
  161. err = dbClient.CreateBouncer("test", "127.0.0.1", middlewares.HashSHA512(apiKey))
  162. if err != nil {
  163. return "", fmt.Errorf("unable to create blocker: %s", err)
  164. }
  165. return apiKey, nil
  166. }
  167. func TestWithWrongDBConfig(t *testing.T) {
  168. config := LoadTestConfig()
  169. config.API.Server.DbConfig.Type = "test"
  170. apiServer, err := NewServer(config.API.Server)
  171. assert.Equal(t, apiServer, &APIServer{})
  172. assert.Equal(t, "unable to init database client: unknown database type", err.Error())
  173. }
  174. func TestWithWrongFlushConfig(t *testing.T) {
  175. config := LoadTestConfig()
  176. maxItems := -1
  177. config.API.Server.DbConfig.Flush.MaxItems = &maxItems
  178. apiServer, err := NewServer(config.API.Server)
  179. assert.Equal(t, apiServer, &APIServer{})
  180. assert.Equal(t, "max_items can't be zero or negative number", err.Error())
  181. }
  182. func TestUnknownPath(t *testing.T) {
  183. router, err := NewAPITest()
  184. if err != nil {
  185. log.Fatalf("unable to run local API: %s", err)
  186. }
  187. w := httptest.NewRecorder()
  188. req, _ := http.NewRequest("GET", "/test", nil)
  189. req.Header.Set("User-Agent", UserAgent)
  190. router.ServeHTTP(w, req)
  191. assert.Equal(t, 404, w.Code)
  192. }
  193. /*
  194. ListenURI string `yaml:"listen_uri,omitempty"` //127.0.0.1:8080
  195. TLS *TLSCfg `yaml:"tls"`
  196. DbConfig *DatabaseCfg `yaml:"-"`
  197. LogDir string `yaml:"-"`
  198. LogMedia string `yaml:"-"`
  199. OnlineClient *OnlineApiClientCfg `yaml:"online_client"`
  200. ProfilesPath string `yaml:"profiles_path,omitempty"`
  201. Profiles []*ProfileCfg `yaml:"-"`
  202. LogLevel *log.Level `yaml:"log_level"`
  203. UseForwardedForHeaders bool `yaml:"use_forwarded_for_headers,omitempty"`
  204. */
  205. func TestLoggingDebugToFileConfig(t *testing.T) {
  206. /*declare settings*/
  207. maxAge := "1h"
  208. flushConfig := csconfig.FlushDBCfg{
  209. MaxAge: &maxAge,
  210. }
  211. dbconfig := csconfig.DatabaseCfg{
  212. Type: "sqlite",
  213. DbPath: "./ent",
  214. Flush: &flushConfig,
  215. }
  216. cfg := csconfig.LocalApiServerCfg{
  217. ListenURI: "127.0.0.1:8080",
  218. LogMedia: "file",
  219. LogDir: ".",
  220. DbConfig: &dbconfig,
  221. }
  222. lvl := log.DebugLevel
  223. expectedFile := "./crowdsec_api.log"
  224. expectedLines := []string{"/test42"}
  225. cfg.LogLevel = &lvl
  226. os.Remove("./crowdsec.log")
  227. os.Remove(expectedFile)
  228. // Configure logging
  229. if err := types.SetDefaultLoggerConfig(cfg.LogMedia, cfg.LogDir, *cfg.LogLevel); err != nil {
  230. t.Fatal(err.Error())
  231. }
  232. api, err := NewServer(&cfg)
  233. if err != nil {
  234. t.Fatalf("failed to create api : %s", err)
  235. }
  236. if api == nil {
  237. t.Fatalf("failed to create api #2 is nbill")
  238. }
  239. w := httptest.NewRecorder()
  240. req, _ := http.NewRequest("GET", "/test42", nil)
  241. req.Header.Set("User-Agent", UserAgent)
  242. api.router.ServeHTTP(w, req)
  243. assert.Equal(t, 404, w.Code)
  244. //wait for the request to happen
  245. time.Sleep(500 * time.Millisecond)
  246. //check file content
  247. data, err := ioutil.ReadFile(expectedFile)
  248. if err != nil {
  249. t.Fatalf("failed to read file : %s", err)
  250. }
  251. for _, expectedStr := range expectedLines {
  252. if !strings.Contains(string(data), expectedStr) {
  253. t.Fatalf("expected %s in %s", expectedStr, string(data))
  254. }
  255. }
  256. os.Remove("./crowdsec.log")
  257. os.Remove(expectedFile)
  258. }
  259. func TestLoggingErrorToFileConfig(t *testing.T) {
  260. /*declare settings*/
  261. maxAge := "1h"
  262. flushConfig := csconfig.FlushDBCfg{
  263. MaxAge: &maxAge,
  264. }
  265. dbconfig := csconfig.DatabaseCfg{
  266. Type: "sqlite",
  267. DbPath: "./ent",
  268. Flush: &flushConfig,
  269. }
  270. cfg := csconfig.LocalApiServerCfg{
  271. ListenURI: "127.0.0.1:8080",
  272. LogMedia: "file",
  273. LogDir: ".",
  274. DbConfig: &dbconfig,
  275. }
  276. lvl := log.ErrorLevel
  277. expectedFile := "./crowdsec_api.log"
  278. cfg.LogLevel = &lvl
  279. os.Remove("./crowdsec.log")
  280. os.Remove(expectedFile)
  281. // Configure logging
  282. if err := types.SetDefaultLoggerConfig(cfg.LogMedia, cfg.LogDir, *cfg.LogLevel); err != nil {
  283. t.Fatal(err.Error())
  284. }
  285. api, err := NewServer(&cfg)
  286. if err != nil {
  287. t.Fatalf("failed to create api : %s", err)
  288. }
  289. if api == nil {
  290. t.Fatalf("failed to create api #2 is nbill")
  291. }
  292. w := httptest.NewRecorder()
  293. req, _ := http.NewRequest("GET", "/test42", nil)
  294. req.Header.Set("User-Agent", UserAgent)
  295. api.router.ServeHTTP(w, req)
  296. assert.Equal(t, 404, w.Code)
  297. //wait for the request to happen
  298. time.Sleep(500 * time.Millisecond)
  299. //check file content
  300. _, err = ioutil.ReadFile(expectedFile)
  301. if err == nil {
  302. t.Fatalf("file should be empty")
  303. }
  304. os.Remove("./crowdsec.log")
  305. os.Remove(expectedFile)
  306. }