github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/monitor/remoteapi/server/server_test.go (about) 1 package server 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "strconv" 11 "testing" 12 13 "github.com/golang/mock/gomock" 14 . "github.com/smartystreets/goconvey/convey" 15 "go.aporeto.io/enforcerd/trireme-lib/common" 16 "go.aporeto.io/enforcerd/trireme-lib/monitor/processor/mockprocessor" 17 "go.aporeto.io/enforcerd/trireme-lib/monitor/registerer" 18 ) 19 20 func TestNewEventServer(t *testing.T) { 21 Convey("When I create a new server", t, func() { 22 reg := registerer.New() 23 s, err := NewEventServer("/tmp/trireme.sock", reg) 24 Convey("The object should be correct", func() { 25 So(err, ShouldBeNil) 26 So(s, ShouldNotBeNil) 27 So(s.socketPath, ShouldResemble, "/tmp/trireme.sock") 28 So(s.registerer, ShouldEqual, reg) 29 }) 30 }) 31 } 32 33 func TestValidateUser(t *testing.T) { 34 Convey("When I try to validate a user", t, func() { 35 36 Convey("When I get a bad remote address, it should fail", func() { 37 r := &http.Request{} 38 r.RemoteAddr = "badpath" 39 event := &common.EventInfo{} 40 41 err := validateUser(r, event) 42 So(err, ShouldNotBeNil) 43 }) 44 45 Convey("When I issue the request as a superuser it should always succeed", func() { 46 r := &http.Request{} 47 r.RemoteAddr = "0:0:1000" 48 event := &common.EventInfo{} 49 50 err := validateUser(r, event) 51 So(err, ShouldBeNil) 52 }) 53 54 Convey("When I issue the request as a regular user with a bad process it should fail", func() { 55 r := &http.Request{} 56 r.RemoteAddr = "1:10:1000" 57 event := &common.EventInfo{PID: -1} 58 59 err := validateUser(r, event) 60 So(err, ShouldNotBeNil) 61 }) 62 63 Convey("When I issue the request as a regular user to a foreign process", func() { 64 65 myuid := strconv.Itoa(os.Getuid()) 66 myguyid := strconv.Itoa(os.Getgid()) 67 mypid := int32(os.Getpid()) 68 mypidstring := strconv.Itoa(int(mypid)) 69 70 r := &http.Request{} 71 r.RemoteAddr = myuid + ":" + myguyid + ":" + mypidstring 72 event := &common.EventInfo{PID: 0} 73 74 err := validateUser(r, event) 75 So(err, ShouldNotBeNil) 76 }) 77 78 Convey("When I issue the request as a regular user with valid pid", func() { 79 80 myuid := strconv.Itoa(os.Getuid()) 81 myguyid := strconv.Itoa(os.Getgid()) 82 mypid := int32(os.Getpid()) 83 mypidstring := strconv.Itoa(int(mypid)) 84 85 r := &http.Request{} 86 r.RemoteAddr = myuid + ":" + myguyid + ":" + mypidstring 87 event := &common.EventInfo{PID: mypid} 88 89 err := validateUser(r, event) 90 So(err, ShouldBeNil) 91 }) 92 93 }) 94 } 95 96 func TestValidateTypes(t *testing.T) { 97 Convey("When I validate the types of an event", t, func() { 98 99 Convey("If I have a bad eventtype it should error.", func() { 100 event := &common.EventInfo{ 101 EventType: common.Event(123), 102 } 103 104 err := validateTypes(event) 105 So(err, ShouldNotBeNil) 106 }) 107 108 Convey("If I have a bad PUType it should error.", func() { 109 event := &common.EventInfo{ 110 EventType: common.EventStart, 111 PUType: common.PUType(123), 112 } 113 114 err := validateTypes(event) 115 So(err, ShouldNotBeNil) 116 }) 117 118 Convey("If the event name has utf8 charaters and it is NOT UIDPAM PU, it should succeed.", func() { 119 event := &common.EventInfo{ 120 EventType: common.EventStart, 121 PUType: common.ContainerPU, 122 Name: "utf8-_!@#%&\" (*)+.,/$!:;<>=?{}~", 123 } 124 125 err := validateTypes(event) 126 So(err, ShouldBeNil) 127 }) 128 129 Convey("If the cgroup has bad charaters, it should error.", func() { 130 event := &common.EventInfo{ 131 EventType: common.EventStart, 132 PUType: common.ContainerPU, 133 Name: "Container", 134 Cgroup: "/potatoes", 135 } 136 137 err := validateTypes(event) 138 So(err, ShouldNotBeNil) 139 }) 140 141 Convey("If the namespace path has bad charaters, it should error.", func() { 142 event := &common.EventInfo{ 143 EventType: common.EventStart, 144 PUType: common.ContainerPU, 145 Name: "Container", 146 Cgroup: "/trireme/123", 147 NS: "!@##$!#", 148 } 149 150 err := validateTypes(event) 151 So(err, ShouldNotBeNil) 152 }) 153 154 Convey("If the IPs have a bad name, it should error.", func() { 155 event := &common.EventInfo{ 156 EventType: common.EventStart, 157 PUType: common.ContainerPU, 158 Name: "Container", 159 Cgroup: "/trireme/123", 160 NS: "/var/run/docker/netns/6f7287cc342b", 161 IPs: map[string]string{"^^^": "123"}, 162 } 163 164 err := validateTypes(event) 165 So(err, ShouldNotBeNil) 166 }) 167 168 Convey("If the IP address is bad, it should error.", func() { 169 event := &common.EventInfo{ 170 EventType: common.EventStart, 171 PUType: common.ContainerPU, 172 Name: "Container", 173 Cgroup: "/trireme/123", 174 NS: "/var/run/docker/netns/6f7287cc342b", 175 IPs: map[string]string{"bridge": "123"}, 176 } 177 178 err := validateTypes(event) 179 So(err, ShouldNotBeNil) 180 }) 181 182 Convey("If all the types are correct, it should succeed.", func() { 183 event := &common.EventInfo{ 184 EventType: common.EventStart, 185 PUType: common.ContainerPU, 186 Name: "Container", 187 Cgroup: "/trireme/123", 188 NS: "/var/run/docker/netns/6f7287cc342b", 189 IPs: map[string]string{"bridge": "172.17.0.1"}, 190 } 191 192 err := validateTypes(event) 193 So(err, ShouldBeNil) 194 }) 195 196 }) 197 } 198 199 func TestValidateEvent(t *testing.T) { 200 Convey("When I validate events", t, func() { 201 202 Convey("If I get a Create with no HostService, and PUID is nil, I should update it.", func() { 203 event := &common.EventInfo{ 204 EventType: common.EventCreate, 205 PID: 1, 206 HostService: false, 207 } 208 209 err := validateEvent(event) 210 So(err, ShouldBeNil) 211 So(event.PUID, ShouldResemble, "1") 212 }) 213 214 Convey("If I get a Create with no HostService, and PUID is not nil, I should get the right PUID", func() { 215 event := &common.EventInfo{ 216 EventType: common.EventCreate, 217 PID: 1, 218 HostService: false, 219 PUID: "mypu", 220 } 221 222 err := validateEvent(event) 223 So(err, ShouldBeNil) 224 So(event.PUID, ShouldResemble, "mypu") 225 }) 226 227 Convey("If I get a Create with the HostService and no networktraffic only, I should get PUID with the same name", func() { 228 event := &common.EventInfo{ 229 EventType: common.EventCreate, 230 PID: 1, 231 HostService: true, 232 NetworkOnlyTraffic: false, 233 PUID: "mypu", 234 } 235 236 err := validateEvent(event) 237 So(err, ShouldBeNil) 238 So(event.PUID, ShouldResemble, "mypu") 239 }) 240 241 Convey("If I get a Create with the HostService and networktraffic only, I should get PUID as my name", func() { 242 event := &common.EventInfo{ 243 EventType: common.EventCreate, 244 PID: 1, 245 HostService: true, 246 NetworkOnlyTraffic: true, 247 Name: "myservice", 248 PUID: "mypu", 249 } 250 251 err := validateEvent(event) 252 So(err, ShouldBeNil) 253 So(event.PUID, ShouldResemble, "mypu") 254 }) 255 256 Convey("If I get a Stop event and cgroup is in the right format, it should return nil.", func() { 257 event := &common.EventInfo{ 258 EventType: common.EventStop, 259 Cgroup: "/trireme/1234", 260 } 261 262 err := validateEvent(event) 263 So(err, ShouldBeNil) 264 }) 265 266 Convey("If I get a Stop event and cgroup is in the wrong format, it should error.", func() { 267 event := &common.EventInfo{ 268 EventType: common.EventStop, 269 Cgroup: "/potatoes", 270 } 271 272 err := validateEvent(event) 273 So(err, ShouldNotBeNil) 274 }) 275 276 }) 277 } 278 279 func TestCreate(t *testing.T) { 280 ctrl := gomock.NewController(t) 281 defer ctrl.Finish() 282 283 Convey("Given a new server", t, func() { 284 reg := registerer.New() 285 s, err := NewEventServer("/tmp/trireme.sock", reg) 286 proc := mockprocessor.NewMockProcessor(ctrl) 287 procerr := reg.RegisterProcessor(common.ContainerPU, proc) 288 So(procerr, ShouldBeNil) 289 290 So(err, ShouldBeNil) 291 292 Convey("Given a valid event, I should get 200 response.", func() { 293 event := &common.EventInfo{ 294 EventType: common.EventStart, 295 PUType: common.ContainerPU, 296 PID: int32(os.Getpid()), 297 Name: "Container", 298 Cgroup: "/trireme/123", 299 NS: "/var/run/docker/netns/6f7287cc342b", 300 IPs: map[string]string{"bridge": "172.17.0.1"}, 301 } 302 303 proc.EXPECT().Start(gomock.Any(), gomock.Any()).Return(nil) 304 305 b := new(bytes.Buffer) 306 err := json.NewEncoder(b).Encode(event) 307 So(err, ShouldBeNil) 308 309 req := httptest.NewRequest("POST", "http://unix", b) 310 req.RemoteAddr = strconv.Itoa(os.Getuid()) + ":" + strconv.Itoa(os.Getgid()) + ":" + strconv.Itoa(int(event.PID)) 311 w := httptest.NewRecorder() 312 s.create(w, req) 313 314 So(w.Result().StatusCode, ShouldEqual, http.StatusAccepted) 315 }) 316 317 Convey("Given bad json a BadRequest", func() { 318 319 b := new(bytes.Buffer) 320 b.WriteString("garbage") 321 322 req := httptest.NewRequest("POST", "http://unix", b) 323 324 w := httptest.NewRecorder() 325 s.create(w, req) 326 327 So(w.Result().StatusCode, ShouldEqual, http.StatusBadRequest) 328 }) 329 330 Convey("Given bad event type, I should get BadRequest ", func() { 331 event := &common.EventInfo{ 332 EventType: common.EventStart, 333 PUType: common.ContainerPU, 334 PID: -1, 335 Name: "^^^^", 336 Cgroup: "/trireme/123", 337 NS: "/var/run/docker/netns/6f7287cc342b", 338 IPs: map[string]string{"bridge": "172.17.0.1", "ip": "thisisnotip"}, 339 } 340 341 b := new(bytes.Buffer) 342 err := json.NewEncoder(b).Encode(event) 343 So(err, ShouldBeNil) 344 345 req := httptest.NewRequest("POST", "http://unix", b) 346 // req.RemoteAddr = strconv.Itoa(os.Getuid()) + ":" + strconv.Itoa(os.Getgid()) + ":" + strconv.Itoa(int(event.PID)) 347 w := httptest.NewRecorder() 348 s.create(w, req) 349 350 So(w.Result().StatusCode, ShouldEqual, http.StatusBadRequest) 351 }) 352 353 Convey("Given a bad user request, I should get StatusForbidden ", func() { 354 event := &common.EventInfo{ 355 EventType: common.EventStart, 356 PUType: common.ContainerPU, 357 PID: 1, 358 Name: "name", 359 Cgroup: "/trireme/123", 360 NS: "/var/run/docker/netns/6f7287cc342b", 361 IPs: map[string]string{"bridge": "172.17.0.1"}, 362 } 363 364 b := new(bytes.Buffer) 365 err := json.NewEncoder(b).Encode(event) 366 So(err, ShouldBeNil) 367 368 req := httptest.NewRequest("POST", "http://unix", b) 369 req.RemoteAddr = strconv.Itoa(os.Getuid()) + ":" + strconv.Itoa(os.Getgid()) + ":" + strconv.Itoa(int(event.PID)) 370 w := httptest.NewRecorder() 371 s.create(w, req) 372 373 So(w.Result().StatusCode, ShouldEqual, http.StatusForbidden) 374 }) 375 376 Convey("Given a bad event, I should get BadRequest ", func() { 377 event := &common.EventInfo{ 378 EventType: common.EventStart, 379 PUType: common.ContainerPU, 380 PID: int32(os.Getpid()), 381 Name: "", 382 Cgroup: "/trireme/123", 383 NS: "/var/run/docker/netns/6f7287cc342b", 384 IPs: map[string]string{"bridge": "172.17.0.1"}, 385 HostService: true, 386 NetworkOnlyTraffic: true, 387 } 388 389 b := new(bytes.Buffer) 390 err := json.NewEncoder(b).Encode(event) 391 So(err, ShouldBeNil) 392 393 req := httptest.NewRequest("POST", "http://unix", b) 394 req.RemoteAddr = strconv.Itoa(os.Getuid()) + ":" + strconv.Itoa(os.Getgid()) + ":" + strconv.Itoa(int(event.PID)) 395 w := httptest.NewRecorder() 396 s.create(w, req) 397 398 So(w.Result().StatusCode, ShouldEqual, http.StatusBadRequest) 399 }) 400 401 Convey("Given a valid event,where the processor fails, I should get InternalServerError.", func() { 402 event := &common.EventInfo{ 403 EventType: common.EventStart, 404 PUType: common.ContainerPU, 405 PID: int32(os.Getpid()), 406 Name: "Container", 407 Cgroup: "/trireme/123", 408 NS: "/var/run/docker/netns/6f7287cc342b", 409 IPs: map[string]string{"bridge": "172.17.0.1"}, 410 } 411 412 proc.EXPECT().Start(gomock.Any(), gomock.Any()).Return(errors.New("some error")) 413 414 b := new(bytes.Buffer) 415 err := json.NewEncoder(b).Encode(event) 416 So(err, ShouldBeNil) 417 418 req := httptest.NewRequest("POST", "http://unix", b) 419 req.RemoteAddr = strconv.Itoa(os.Getuid()) + ":" + strconv.Itoa(os.Getgid()) + ":" + strconv.Itoa(int(event.PID)) 420 w := httptest.NewRecorder() 421 s.create(w, req) 422 423 So(w.Result().StatusCode, ShouldEqual, http.StatusInternalServerError) 424 }) 425 426 }) 427 428 }