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 }