github.com/hpcng/singularity@v3.1.1+incompatible/pkg/util/capabilities/config_test.go (about)

     1  // Copyright (c) 2018-2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package capabilities
     7  
     8  import (
     9  	"bytes"
    10  	"reflect"
    11  	"testing"
    12  )
    13  
    14  type readFromTest struct {
    15  	c          Config
    16  	shouldFail bool
    17  }
    18  
    19  type readWriteTest struct {
    20  	name string
    21  	c    Config
    22  }
    23  
    24  func TestReadFromWriteTo(t *testing.T) {
    25  	testsPass := []readWriteTest{
    26  		readWriteTest{
    27  			name: "empty config",
    28  			c: Config{
    29  				Users:  map[string][]string{},
    30  				Groups: map[string][]string{},
    31  			},
    32  		},
    33  		readWriteTest{
    34  			name: "config with stuff",
    35  			c: Config{
    36  				Users: map[string][]string{
    37  					"user1": []string{"CAP_SYS_ADMIN"},
    38  					"user2": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
    39  				},
    40  				Groups: map[string][]string{
    41  					"user1": []string{"CAP_SYS_ADMIN"},
    42  					"user2": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
    43  				},
    44  			},
    45  		},
    46  	}
    47  
    48  	for _, test := range testsPass {
    49  		t.Run(test.name, func(t *testing.T) {
    50  			var r bytes.Buffer
    51  
    52  			test.c.WriteTo(&r)
    53  
    54  			new, err := ReadFrom(&r)
    55  			if err != nil {
    56  				t.Errorf("unexpected failure running %s test: %s", test.name, err)
    57  			}
    58  
    59  			if !reflect.DeepEqual(test.c, *new) {
    60  				t.Errorf("failed to read/write config:\n\thave: %v\n\twant: %v", test.c, *new)
    61  			}
    62  		})
    63  	}
    64  
    65  	t.Run("empty config no data", func(t *testing.T) {
    66  		var r bytes.Buffer
    67  
    68  		_, err := ReadFrom(&r)
    69  
    70  		if err != nil {
    71  			t.Errorf("unexpected failure running %s test: %s", t.Name(), err)
    72  		}
    73  
    74  	})
    75  
    76  }
    77  
    78  func checkReadFrom(t *testing.T, confExpected Config, shouldFail bool) {
    79  	var r *bytes.Buffer
    80  
    81  	confExpected.WriteTo(r)
    82  
    83  	confActual, err := ReadFrom(r)
    84  	if err == nil && shouldFail {
    85  		t.Errorf("unexpected success running test")
    86  		return
    87  	} else if err != nil && !shouldFail {
    88  		t.Errorf("unexpected failure running test")
    89  		return
    90  	}
    91  
    92  	if !reflect.DeepEqual(confExpected, *confActual) {
    93  		t.Errorf("ReadFrom returned incorrect capability config")
    94  	}
    95  }
    96  
    97  type capTest struct {
    98  	name string
    99  	old  Config
   100  	new  Config
   101  	id   string
   102  	caps []string
   103  }
   104  
   105  func TestAddUserCaps(t *testing.T) {
   106  	testsPass := []capTest{
   107  		capTest{
   108  			name: "add existing user single cap",
   109  			old: Config{
   110  				Users: map[string][]string{
   111  					"root": []string{"CAP_SYS_ADMIN"},
   112  				},
   113  			},
   114  			new: Config{
   115  				Users: map[string][]string{
   116  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   117  				},
   118  			},
   119  			id:   "root",
   120  			caps: []string{"CAP_DAC_OVERRIDE"},
   121  		},
   122  		capTest{
   123  			name: "add existing user multiple caps",
   124  			old: Config{
   125  				Users: map[string][]string{
   126  					"user1": []string{"CAP_SYS_ADMIN"},
   127  				},
   128  			},
   129  			new: Config{
   130  				Users: map[string][]string{
   131  					"user1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   132  				},
   133  			},
   134  			id:   "user1",
   135  			caps: []string{"CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   136  		},
   137  		capTest{
   138  			name: "add new user",
   139  			old: Config{
   140  				Users: map[string][]string{
   141  					"root": []string{"CAP_SYS_ADMIN"},
   142  				},
   143  			},
   144  			new: Config{
   145  				Users: map[string][]string{
   146  					"root":  []string{"CAP_SYS_ADMIN"},
   147  					"user1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   148  				},
   149  			},
   150  			id:   "user1",
   151  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   152  		},
   153  		capTest{
   154  			name: "add duplicate cap",
   155  			old: Config{
   156  				Users: map[string][]string{
   157  					"root": []string{"CAP_SYS_ADMIN"},
   158  				},
   159  			},
   160  			new: Config{
   161  				Users: map[string][]string{
   162  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   163  				},
   164  			},
   165  			id:   "root",
   166  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   167  		},
   168  	}
   169  
   170  	for _, test := range testsPass {
   171  		t.Run(test.name, func(t *testing.T) {
   172  			if err := test.old.AddUserCaps(test.id, test.caps); err != nil {
   173  				t.Error("failed to add capability to config")
   174  			}
   175  
   176  			if !reflect.DeepEqual(test.old, test.new) {
   177  				t.Errorf("AddUserCaps failed to set config:\n\thave: %v\n\twant: %v", test.old, test.new)
   178  			}
   179  		})
   180  	}
   181  
   182  	testFail := capTest{
   183  		name: "add bad cap fail",
   184  		old: Config{
   185  			Users: map[string][]string{
   186  				"root": []string{"CAP_SYS_ADMIN"},
   187  			},
   188  		},
   189  		new: Config{
   190  			Users: map[string][]string{
   191  				"root": []string{"CAP_SYS_ADMIN"},
   192  			},
   193  		},
   194  		id:   "root",
   195  		caps: []string{"CAP_BAD_WRONG_INCORRECT_BAD"},
   196  	}
   197  
   198  	t.Run(testFail.name, func(t *testing.T) {
   199  		if err := testFail.old.AddUserCaps(testFail.id, testFail.caps); err == nil {
   200  			t.Error("unexpected success adding non-existent capability")
   201  		}
   202  	})
   203  }
   204  
   205  func TestAddGroupCaps(t *testing.T) {
   206  	testsPass := []capTest{
   207  		capTest{
   208  			name: "add existing group single cap",
   209  			old: Config{
   210  				Groups: map[string][]string{
   211  					"root": []string{"CAP_SYS_ADMIN"},
   212  				},
   213  			},
   214  			new: Config{
   215  				Groups: map[string][]string{
   216  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   217  				},
   218  			},
   219  			id:   "root",
   220  			caps: []string{"CAP_DAC_OVERRIDE"},
   221  		},
   222  		capTest{
   223  			name: "add existing group multiple caps",
   224  			old: Config{
   225  				Groups: map[string][]string{
   226  					"group1": []string{"CAP_SYS_ADMIN"},
   227  				},
   228  			},
   229  			new: Config{
   230  				Groups: map[string][]string{
   231  					"group1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   232  				},
   233  			},
   234  			id:   "group1",
   235  			caps: []string{"CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   236  		},
   237  		capTest{
   238  			name: "add new group",
   239  			old: Config{
   240  				Groups: map[string][]string{
   241  					"root": []string{"CAP_SYS_ADMIN"},
   242  				},
   243  			},
   244  			new: Config{
   245  				Groups: map[string][]string{
   246  					"root":   []string{"CAP_SYS_ADMIN"},
   247  					"group1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   248  				},
   249  			},
   250  			id:   "group1",
   251  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   252  		},
   253  		capTest{
   254  			name: "add duplicate cap",
   255  			old: Config{
   256  				Groups: map[string][]string{
   257  					"root": []string{"CAP_SYS_ADMIN"},
   258  				},
   259  			},
   260  			new: Config{
   261  				Groups: map[string][]string{
   262  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   263  				},
   264  			},
   265  			id:   "root",
   266  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   267  		},
   268  	}
   269  
   270  	for _, test := range testsPass {
   271  		t.Run(test.name, func(t *testing.T) {
   272  			if err := test.old.AddGroupCaps(test.id, test.caps); err != nil {
   273  				t.Error("failed to add capability to config")
   274  			}
   275  
   276  			if !reflect.DeepEqual(test.old, test.new) {
   277  				t.Errorf("AddGroupCaps failed to set config:\n\thave: %v\n\twant: %v", test.old, test.new)
   278  			}
   279  		})
   280  	}
   281  
   282  	testFail := capTest{
   283  		name: "add bad cap fail",
   284  		old: Config{
   285  			Groups: map[string][]string{
   286  				"root": []string{"CAP_SYS_ADMIN"},
   287  			},
   288  		},
   289  		new: Config{
   290  			Groups: map[string][]string{
   291  				"root": []string{"CAP_SYS_ADMIN"},
   292  			},
   293  		},
   294  		id:   "root",
   295  		caps: []string{"CAP_BAD_WRONG_INCORRECT_BAD"},
   296  	}
   297  
   298  	t.Run(testFail.name, func(t *testing.T) {
   299  		if err := testFail.old.AddGroupCaps(testFail.id, testFail.caps); err == nil {
   300  			t.Error("unexpected success adding non-existent capability")
   301  		}
   302  	})
   303  }
   304  
   305  func TestDropUserCaps(t *testing.T) {
   306  	testsPass := []capTest{
   307  		capTest{
   308  			name: "drop existing user single cap",
   309  			old: Config{
   310  				Users: map[string][]string{
   311  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   312  				},
   313  			},
   314  			new: Config{
   315  				Users: map[string][]string{
   316  					"root": []string{"CAP_SYS_ADMIN"},
   317  				},
   318  			},
   319  			id:   "root",
   320  			caps: []string{"CAP_DAC_OVERRIDE"},
   321  		},
   322  		capTest{
   323  			name: "drop existing user multiple caps",
   324  			old: Config{
   325  				Users: map[string][]string{
   326  					"user1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   327  				},
   328  			},
   329  			new: Config{
   330  				Users: map[string][]string{
   331  					"user1": []string{"CAP_SYS_ADMIN"},
   332  				},
   333  			},
   334  			id:   "user1",
   335  			caps: []string{"CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   336  		},
   337  		capTest{
   338  			name: "drop duplicate cap",
   339  			old: Config{
   340  				Users: map[string][]string{
   341  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   342  				},
   343  			},
   344  			new: Config{
   345  				Users: map[string][]string{
   346  					"root": []string{},
   347  				},
   348  			},
   349  			id:   "root",
   350  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   351  		},
   352  	}
   353  
   354  	for _, test := range testsPass {
   355  		t.Run(test.name, func(t *testing.T) {
   356  			if err := test.old.DropUserCaps(test.id, test.caps); err != nil {
   357  				t.Error("failed to drop capability to config")
   358  			}
   359  
   360  			if !reflect.DeepEqual(test.old, test.new) {
   361  				t.Errorf("DropUserCaps failed to set config:\n\thave: %v\n\twant: %v", test.old, test.new)
   362  			}
   363  		})
   364  	}
   365  
   366  	testsFail := []capTest{
   367  		capTest{
   368  			name: "drop bad cap fail",
   369  			old: Config{
   370  				Users: map[string][]string{
   371  					"root": []string{"CAP_SYS_ADMIN"},
   372  				},
   373  			},
   374  			new: Config{
   375  				Users: map[string][]string{
   376  					"root": []string{"CAP_SYS_ADMIN"},
   377  				},
   378  			},
   379  			id:   "root",
   380  			caps: []string{"CAP_BAD_WRONG_INCORRECT_BAD"},
   381  		},
   382  		capTest{
   383  			name: "drop bad user fail",
   384  			old: Config{
   385  				Users: map[string][]string{
   386  					"root": []string{"CAP_SYS_ADMIN"},
   387  				},
   388  			},
   389  			new: Config{
   390  				Users: map[string][]string{
   391  					"root": []string{"CAP_SYS_ADMIN"},
   392  				},
   393  			},
   394  			id:   "non_existent_user",
   395  			caps: []string{"CAP_SYS_ADMIN"},
   396  		},
   397  	}
   398  
   399  	for _, test := range testsFail {
   400  		t.Run(test.name, func(t *testing.T) {
   401  			if err := test.old.DropUserCaps(test.id, test.caps); err == nil {
   402  				t.Error("unexpected success dropping non-existent capability")
   403  			}
   404  		})
   405  	}
   406  }
   407  
   408  func TestDropGroupCaps(t *testing.T) {
   409  	testsPass := []capTest{
   410  		capTest{
   411  			name: "drop existing group single cap",
   412  			old: Config{
   413  				Groups: map[string][]string{
   414  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   415  				},
   416  			},
   417  			new: Config{
   418  				Groups: map[string][]string{
   419  					"root": []string{"CAP_SYS_ADMIN"},
   420  				},
   421  			},
   422  			id:   "root",
   423  			caps: []string{"CAP_DAC_OVERRIDE"},
   424  		},
   425  		capTest{
   426  			name: "drop existing group multiple caps",
   427  			old: Config{
   428  				Groups: map[string][]string{
   429  					"group1": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   430  				},
   431  			},
   432  			new: Config{
   433  				Groups: map[string][]string{
   434  					"group1": []string{"CAP_SYS_ADMIN"},
   435  				},
   436  			},
   437  			id:   "group1",
   438  			caps: []string{"CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   439  		},
   440  		capTest{
   441  			name: "drop duplicate cap",
   442  			old: Config{
   443  				Groups: map[string][]string{
   444  					"root": []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   445  				},
   446  			},
   447  			new: Config{
   448  				Groups: map[string][]string{
   449  					"root": []string{},
   450  				},
   451  			},
   452  			id:   "root",
   453  			caps: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE", "CAP_CHOWN"},
   454  		},
   455  	}
   456  
   457  	for _, test := range testsPass {
   458  		t.Run(test.name, func(t *testing.T) {
   459  			if err := test.old.DropGroupCaps(test.id, test.caps); err != nil {
   460  				t.Error("failed to drop capability to config")
   461  			}
   462  
   463  			if !reflect.DeepEqual(test.old, test.new) {
   464  				t.Errorf("DropGroupCaps failed to set config:\n\thave: %v\n\twant: %v", test.old, test.new)
   465  			}
   466  		})
   467  	}
   468  
   469  	testsFail := []capTest{
   470  		capTest{
   471  			name: "drop bad cap fail",
   472  			old: Config{
   473  				Groups: map[string][]string{
   474  					"root": []string{"CAP_SYS_ADMIN"},
   475  				},
   476  			},
   477  			new: Config{
   478  				Groups: map[string][]string{
   479  					"root": []string{"CAP_SYS_ADMIN"},
   480  				},
   481  			},
   482  			id:   "root",
   483  			caps: []string{"CAP_BAD_WRONG_INCORRECT_BAD"},
   484  		},
   485  		capTest{
   486  			name: "drop bad group fail",
   487  			old: Config{
   488  				Groups: map[string][]string{
   489  					"root": []string{"CAP_SYS_ADMIN"},
   490  				},
   491  			},
   492  			new: Config{
   493  				Groups: map[string][]string{
   494  					"root": []string{"CAP_SYS_ADMIN"},
   495  				},
   496  			},
   497  			id:   "non_existent_group",
   498  			caps: []string{"CAP_SYS_ADMIN"},
   499  		},
   500  	}
   501  
   502  	for _, test := range testsFail {
   503  		t.Run(test.name, func(t *testing.T) {
   504  			if err := test.old.DropGroupCaps(test.id, test.caps); err == nil {
   505  				t.Error("unexpected success dropping non-existent capability")
   506  			}
   507  		})
   508  	}
   509  }
   510  
   511  func TestListCaps(t *testing.T) {
   512  	conf := Config{
   513  		Users: map[string][]string{
   514  			"root":  []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   515  			"user1": []string{"CAP_CHOWN"},
   516  		},
   517  		Groups: map[string][]string{
   518  			"root":  []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   519  			"user2": []string{"CAP_CHOWN"},
   520  		},
   521  	}
   522  
   523  	if !reflect.DeepEqual(conf.ListUserCaps("root"), conf.Users["root"]) {
   524  		t.Error("user cap lookup failed")
   525  	}
   526  
   527  	if !reflect.DeepEqual(conf.ListGroupCaps("user2"), conf.Groups["user2"]) {
   528  		t.Error("group cap lookup failed")
   529  	}
   530  
   531  	u, g := conf.ListAllCaps()
   532  
   533  	if !reflect.DeepEqual(conf.Users, u) || !reflect.DeepEqual(conf.Groups, g) {
   534  		t.Error("all caps lookup failed")
   535  	}
   536  }
   537  
   538  type capCheckTest struct {
   539  	name         string
   540  	id           string
   541  	caps         []string
   542  	authorized   []string
   543  	unauthorized []string
   544  }
   545  
   546  func TestCheckCaps(t *testing.T) {
   547  	conf := Config{
   548  		Users: map[string][]string{
   549  			"root":  []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   550  			"user1": []string{"CAP_CHOWN", "CAP_SYS_ADMIN"},
   551  			"user2": []string{},
   552  		},
   553  		Groups: map[string][]string{
   554  			"root":  []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   555  			"user1": []string{"CAP_CHOWN", "CAP_SYS_ADMIN"},
   556  			"user2": []string{},
   557  		},
   558  	}
   559  
   560  	testsPass := []capCheckTest{
   561  		capCheckTest{
   562  			name:       "check multiple authorized",
   563  			id:         "root",
   564  			caps:       []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   565  			authorized: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   566  		},
   567  		capCheckTest{
   568  			name:         "check multiple unauthorized",
   569  			id:           "user2",
   570  			caps:         []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   571  			unauthorized: []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   572  		},
   573  		capCheckTest{
   574  			name:         "check multiple authorized & unauthorized",
   575  			id:           "user1",
   576  			caps:         []string{"CAP_SYS_ADMIN", "CAP_DAC_OVERRIDE"},
   577  			authorized:   []string{"CAP_SYS_ADMIN"},
   578  			unauthorized: []string{"CAP_DAC_OVERRIDE"},
   579  		},
   580  	}
   581  
   582  	for _, test := range testsPass {
   583  		t.Run(test.name, func(t *testing.T) {
   584  			aUser, uUser := conf.CheckUserCaps(test.id, test.caps)
   585  			if !reflect.DeepEqual(aUser, test.authorized) {
   586  				t.Errorf("returned incorrect authorized user caps:\n\thave: %v\n\twant: %v", test.authorized, aUser)
   587  			}
   588  
   589  			if !reflect.DeepEqual(uUser, test.unauthorized) {
   590  				t.Errorf("returned incorrect unauthorized user caps:\n\thave: %v\n\twant: %v", test.unauthorized, uUser)
   591  			}
   592  
   593  			aGroup, uGroup := conf.CheckGroupCaps(test.id, test.caps)
   594  			if !reflect.DeepEqual(aGroup, test.authorized) {
   595  				t.Errorf("returned incorrect authorized group caps:\n\thave: %v\n\twant: %v", test.authorized, aGroup)
   596  			}
   597  
   598  			if !reflect.DeepEqual(uGroup, test.unauthorized) {
   599  				t.Errorf("returned incorrect unauthorized group caps:\n\thave: %v\n\twant: %v", test.unauthorized, uGroup)
   600  			}
   601  
   602  		})
   603  	}
   604  
   605  }