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  }