github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/permissions_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names/v5"
     9  	jc "github.com/juju/testing/checkers"
    10  	"go.uber.org/mock/gomock"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/apiserver/authentication"
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/apiserver/facade/mocks"
    16  	"github.com/juju/juju/core/permission"
    17  	"github.com/juju/juju/testing"
    18  )
    19  
    20  type PermissionSuite struct {
    21  	testing.BaseSuite
    22  }
    23  
    24  var _ = gc.Suite(&PermissionSuite{})
    25  
    26  type fakeUserAccess struct {
    27  	subjects []names.UserTag
    28  	objects  []names.Tag
    29  	access   permission.Access
    30  	err      error
    31  }
    32  
    33  func (f *fakeUserAccess) call(subject names.UserTag, object names.Tag) (permission.Access, error) {
    34  	f.subjects = append(f.subjects, subject)
    35  	f.objects = append(f.objects, object)
    36  	return f.access, f.err
    37  }
    38  
    39  func (r *PermissionSuite) TestNoUserTagLacksPermission(c *gc.C) {
    40  	nonUser := names.NewModelTag("beef1beef1-0000-0000-000011112222")
    41  	target := names.NewModelTag("beef1beef2-0000-0000-000011112222")
    42  	hasPermission, err := common.HasPermission((&fakeUserAccess{}).call, nonUser, permission.ReadAccess, target)
    43  	c.Assert(hasPermission, jc.IsFalse)
    44  	c.Assert(err, jc.ErrorIsNil)
    45  }
    46  
    47  func (r *PermissionSuite) TestHasPermission(c *gc.C) {
    48  	testCases := []struct {
    49  		title            string
    50  		userGetterAccess permission.Access
    51  		user             names.UserTag
    52  		target           names.Tag
    53  		access           permission.Access
    54  		expected         bool
    55  	}{
    56  		{
    57  			title:            "user has lesser permissions than required",
    58  			userGetterAccess: permission.ReadAccess,
    59  			user:             names.NewUserTag("validuser"),
    60  			target:           names.NewModelTag("beef1beef2-0000-0000-000011112222"),
    61  			access:           permission.WriteAccess,
    62  			expected:         false,
    63  		},
    64  		{
    65  			title:            "user has equal permission than required",
    66  			userGetterAccess: permission.WriteAccess,
    67  			user:             names.NewUserTag("validuser"),
    68  			target:           names.NewModelTag("beef1beef2-0000-0000-000011112222"),
    69  			access:           permission.WriteAccess,
    70  			expected:         true,
    71  		},
    72  		{
    73  			title:            "user has greater permission than required",
    74  			userGetterAccess: permission.AdminAccess,
    75  			user:             names.NewUserTag("validuser"),
    76  			target:           names.NewModelTag("beef1beef2-0000-0000-000011112222"),
    77  			access:           permission.WriteAccess,
    78  			expected:         true,
    79  		},
    80  		{
    81  			title:            "user requests model permission on controller",
    82  			userGetterAccess: permission.AdminAccess,
    83  			user:             names.NewUserTag("validuser"),
    84  			target:           names.NewModelTag("beef1beef2-0000-0000-000011112222"),
    85  			access:           permission.AddModelAccess,
    86  			expected:         false,
    87  		},
    88  		{
    89  			title:            "user requests controller permission on model",
    90  			userGetterAccess: permission.AdminAccess,
    91  			user:             names.NewUserTag("validuser"),
    92  			target:           names.NewControllerTag("beef1beef2-0000-0000-000011112222"),
    93  			access:           permission.AdminAccess, // notice user has this permission for model.
    94  			expected:         false,
    95  		},
    96  		{
    97  			title:            "controller permissions also work",
    98  			userGetterAccess: permission.SuperuserAccess,
    99  			user:             names.NewUserTag("validuser"),
   100  			target:           names.NewControllerTag("beef1beef2-0000-0000-000011112222"),
   101  			access:           permission.SuperuserAccess,
   102  			expected:         true,
   103  		},
   104  		{
   105  			title:            "cloud permissions work",
   106  			userGetterAccess: permission.AddModelAccess,
   107  			user:             names.NewUserTag("validuser"),
   108  			target:           names.NewCloudTag("mycloud"),
   109  			access:           permission.AddModelAccess,
   110  			expected:         true,
   111  		},
   112  		{
   113  			title:            "user has lesser cloud permissions than required",
   114  			userGetterAccess: permission.NoAccess,
   115  			user:             names.NewUserTag("validuser"),
   116  			target:           names.NewCloudTag("mycloud"),
   117  			access:           permission.AddModelAccess,
   118  			expected:         false,
   119  		},
   120  		{
   121  			title:            "user has lesser offer permissions than required",
   122  			userGetterAccess: permission.ReadAccess,
   123  			user:             names.NewUserTag("validuser"),
   124  			target:           names.NewApplicationOfferTag("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
   125  			access:           permission.WriteAccess,
   126  			expected:         false,
   127  		},
   128  		{
   129  			title:            "user has equal offer permission than required",
   130  			userGetterAccess: permission.ConsumeAccess,
   131  			user:             names.NewUserTag("validuser"),
   132  			target:           names.NewApplicationOfferTag("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
   133  			access:           permission.ConsumeAccess,
   134  			expected:         true,
   135  		},
   136  		{
   137  			title:            "user has greater offer permission than required",
   138  			userGetterAccess: permission.AdminAccess,
   139  			user:             names.NewUserTag("validuser"),
   140  			target:           names.NewApplicationOfferTag("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
   141  			access:           permission.ConsumeAccess,
   142  			expected:         true,
   143  		},
   144  		{
   145  			title:            "user requests controller permission on offer",
   146  			userGetterAccess: permission.ReadAccess,
   147  			user:             names.NewUserTag("validuser"),
   148  			target:           names.NewApplicationOfferTag("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
   149  			access:           permission.AddModelAccess,
   150  			expected:         false,
   151  		},
   152  	}
   153  	for i, t := range testCases {
   154  		userGetter := &fakeUserAccess{
   155  			access: t.userGetterAccess,
   156  		}
   157  		c.Logf("HasPermission test n %d: %s", i, t.title)
   158  		hasPermission, err := common.HasPermission(userGetter.call, t.user, t.access, t.target)
   159  		c.Assert(hasPermission, gc.Equals, t.expected)
   160  		c.Assert(err, jc.ErrorIsNil)
   161  	}
   162  
   163  }
   164  
   165  func (r *PermissionSuite) TestUserGetterErrorReturns(c *gc.C) {
   166  	user := names.NewUserTag("validuser")
   167  	target := names.NewModelTag("beef1beef2-0000-0000-000011112222")
   168  	userGetter := &fakeUserAccess{
   169  		access: permission.NoAccess,
   170  		err:    errors.NotFoundf("a user"),
   171  	}
   172  	hasPermission, err := common.HasPermission(userGetter.call, user, permission.ReadAccess, target)
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	c.Assert(hasPermission, jc.IsFalse)
   175  	c.Assert(userGetter.subjects, gc.HasLen, 1)
   176  	c.Assert(userGetter.subjects[0], gc.DeepEquals, user)
   177  	c.Assert(userGetter.objects, gc.HasLen, 1)
   178  	c.Assert(userGetter.objects[0], gc.DeepEquals, target)
   179  }
   180  
   181  type fakeEveryoneUserAccess struct {
   182  	user     permission.Access
   183  	everyone permission.Access
   184  }
   185  
   186  func (f *fakeEveryoneUserAccess) call(subject names.UserTag, object names.Tag) (permission.Access, error) {
   187  	if subject.Id() == common.EveryoneTagName {
   188  		return f.everyone, nil
   189  	}
   190  	return f.user, nil
   191  }
   192  
   193  func (r *PermissionSuite) TestEveryoneAtExternal(c *gc.C) {
   194  	testCases := []struct {
   195  		title            string
   196  		userGetterAccess permission.Access
   197  		everyoneAccess   permission.Access
   198  		user             names.UserTag
   199  		target           names.Tag
   200  		access           permission.Access
   201  		expected         bool
   202  	}{
   203  		{
   204  			title:            "user has lesser permissions than everyone",
   205  			userGetterAccess: permission.LoginAccess,
   206  			everyoneAccess:   permission.SuperuserAccess,
   207  			user:             names.NewUserTag("validuser@external"),
   208  			target:           names.NewControllerTag("beef1beef2-0000-0000-000011112222"),
   209  			access:           permission.SuperuserAccess,
   210  			expected:         true,
   211  		},
   212  		{
   213  			title:            "user has greater permissions than everyone",
   214  			userGetterAccess: permission.SuperuserAccess,
   215  			everyoneAccess:   permission.LoginAccess,
   216  			user:             names.NewUserTag("validuser@external"),
   217  			target:           names.NewControllerTag("beef1beef2-0000-0000-000011112222"),
   218  			access:           permission.SuperuserAccess,
   219  			expected:         true,
   220  		},
   221  		{
   222  			title:            "everibody not considered if user is local",
   223  			userGetterAccess: permission.LoginAccess,
   224  			everyoneAccess:   permission.SuperuserAccess,
   225  			user:             names.NewUserTag("validuser"),
   226  			target:           names.NewControllerTag("beef1beef2-0000-0000-000011112222"),
   227  			access:           permission.SuperuserAccess,
   228  			expected:         false,
   229  		},
   230  	}
   231  
   232  	for i, t := range testCases {
   233  		userGetter := &fakeEveryoneUserAccess{
   234  			user:     t.userGetterAccess,
   235  			everyone: t.everyoneAccess,
   236  		}
   237  		c.Logf(`HasPermission "everyone" test n %d: %s`, i, t.title)
   238  		hasPermission, err := common.HasPermission(userGetter.call, t.user, t.access, t.target)
   239  		c.Assert(err, jc.ErrorIsNil)
   240  		c.Assert(hasPermission, gc.Equals, t.expected)
   241  	}
   242  }
   243  
   244  func (r *PermissionSuite) TestHasModelAdminSuperUser(c *gc.C) {
   245  	ctrl := gomock.NewController(c)
   246  	defer ctrl.Finish()
   247  
   248  	auth := mocks.NewMockAuthorizer(ctrl)
   249  	auth.EXPECT().HasPermission(permission.SuperuserAccess, testing.ControllerTag).Return(nil)
   250  
   251  	has, err := common.HasModelAdmin(auth, testing.ControllerTag, testing.ModelTag)
   252  	c.Assert(err, jc.ErrorIsNil)
   253  	c.Assert(has, jc.IsTrue)
   254  }
   255  
   256  func (r *PermissionSuite) TestHasModelAdminYes(c *gc.C) {
   257  	ctrl := gomock.NewController(c)
   258  	defer ctrl.Finish()
   259  
   260  	auth := mocks.NewMockAuthorizer(ctrl)
   261  	auth.EXPECT().HasPermission(permission.SuperuserAccess, testing.ControllerTag).Return(authentication.ErrorEntityMissingPermission)
   262  	auth.EXPECT().HasPermission(permission.AdminAccess, testing.ModelTag).Return(nil)
   263  
   264  	has, err := common.HasModelAdmin(auth, testing.ControllerTag, testing.ModelTag)
   265  	c.Assert(err, jc.ErrorIsNil)
   266  	c.Assert(has, jc.IsTrue)
   267  }
   268  
   269  func (r *PermissionSuite) TestHasModelAdminNo(c *gc.C) {
   270  	ctrl := gomock.NewController(c)
   271  	defer ctrl.Finish()
   272  
   273  	auth := mocks.NewMockAuthorizer(ctrl)
   274  	auth.EXPECT().HasPermission(permission.SuperuserAccess, testing.ControllerTag).Return(authentication.ErrorEntityMissingPermission)
   275  	auth.EXPECT().HasPermission(permission.AdminAccess, testing.ModelTag).Return(authentication.ErrorEntityMissingPermission)
   276  
   277  	has, err := common.HasModelAdmin(auth, testing.ControllerTag, testing.ModelTag)
   278  	c.Assert(err, jc.ErrorIsNil)
   279  	c.Assert(has, jc.IsFalse)
   280  }
   281  
   282  func (r *PermissionSuite) TestHasModelAdminError(c *gc.C) {
   283  	ctrl := gomock.NewController(c)
   284  	defer ctrl.Finish()
   285  
   286  	auth := mocks.NewMockAuthorizer(ctrl)
   287  	auth.EXPECT().HasPermission(permission.SuperuserAccess, testing.ControllerTag).Return(authentication.ErrorEntityMissingPermission)
   288  	someError := errors.New("error")
   289  	auth.EXPECT().HasPermission(permission.AdminAccess, testing.ModelTag).Return(someError)
   290  
   291  	has, err := common.HasModelAdmin(auth, testing.ControllerTag, testing.ModelTag)
   292  	c.Assert(err, jc.ErrorIs, someError)
   293  	c.Assert(has, jc.IsFalse)
   294  }