mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-08 18:04:14 +01:00
Improve permission check of packages (#23879)
At first, we have one unified team unit permission which is called `Team.Authorize` in DB. But since https://github.com/go-gitea/gitea/pull/17811, we allowed different units to have different permission. The old code is only designed for the old version. So after #17811, if org users have write permission of other units, but have no permission of packages, they can also get write permission of packages. Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
parent
5cb394ff2f
commit
bbf83f5d4b
8 changed files with 63 additions and 26 deletions
|
@ -75,3 +75,9 @@
|
||||||
uid: 31
|
uid: 31
|
||||||
org_id: 19
|
org_id: 19
|
||||||
is_public: true
|
is_public: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 14
|
||||||
|
uid: 5
|
||||||
|
org_id: 23
|
||||||
|
is_public: false
|
||||||
|
|
|
@ -173,3 +173,14 @@
|
||||||
num_members: 0
|
num_members: 0
|
||||||
includes_all_repositories: false
|
includes_all_repositories: false
|
||||||
can_create_org_repo: true
|
can_create_org_repo: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 17
|
||||||
|
org_id: 23
|
||||||
|
lower_name: team14writeauth
|
||||||
|
name: team14WriteAuth
|
||||||
|
authorize: 2 # write
|
||||||
|
num_repos: 0
|
||||||
|
num_members: 1
|
||||||
|
includes_all_repositories: false
|
||||||
|
can_create_org_repo: true
|
||||||
|
|
|
@ -268,3 +268,9 @@
|
||||||
team_id: 9
|
team_id: 9
|
||||||
type: 1 # code
|
type: 1 # code
|
||||||
access_mode: 1
|
access_mode: 1
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 46
|
||||||
|
team_id: 17
|
||||||
|
type: 9 # package
|
||||||
|
access_mode: 0
|
||||||
|
|
|
@ -99,3 +99,9 @@
|
||||||
org_id: 3
|
org_id: 3
|
||||||
team_id: 14
|
team_id: 14
|
||||||
uid: 2
|
uid: 2
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 18
|
||||||
|
org_id: 23
|
||||||
|
team_id: 17
|
||||||
|
uid: 5
|
||||||
|
|
|
@ -844,8 +844,8 @@
|
||||||
num_following: 0
|
num_following: 0
|
||||||
num_stars: 0
|
num_stars: 0
|
||||||
num_repos: 2
|
num_repos: 2
|
||||||
num_teams: 1
|
num_teams: 2
|
||||||
num_members: 0
|
num_members: 1
|
||||||
visibility: 2
|
visibility: 2
|
||||||
repo_admin_change_team_access: false
|
repo_admin_change_team_access: false
|
||||||
theme: ""
|
theme: ""
|
||||||
|
|
|
@ -212,25 +212,31 @@ func TestGetOrgUsersByUserID(t *testing.T) {
|
||||||
|
|
||||||
orgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: true})
|
orgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: true})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, orgUsers, 2) {
|
if assert.Len(t, orgUsers, 3) {
|
||||||
assert.Equal(t, organization.OrgUser{
|
assert.Equal(t, organization.OrgUser{
|
||||||
ID: orgUsers[0].ID,
|
ID: orgUsers[0].ID,
|
||||||
OrgID: 6,
|
OrgID: 23,
|
||||||
UID: 5,
|
UID: 5,
|
||||||
IsPublic: true,
|
IsPublic: false,
|
||||||
}, *orgUsers[0])
|
}, *orgUsers[0])
|
||||||
assert.Equal(t, organization.OrgUser{
|
assert.Equal(t, organization.OrgUser{
|
||||||
ID: orgUsers[1].ID,
|
ID: orgUsers[1].ID,
|
||||||
|
OrgID: 6,
|
||||||
|
UID: 5,
|
||||||
|
IsPublic: true,
|
||||||
|
}, *orgUsers[1])
|
||||||
|
assert.Equal(t, organization.OrgUser{
|
||||||
|
ID: orgUsers[2].ID,
|
||||||
OrgID: 7,
|
OrgID: 7,
|
||||||
UID: 5,
|
UID: 5,
|
||||||
IsPublic: false,
|
IsPublic: false,
|
||||||
}, *orgUsers[1])
|
}, *orgUsers[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
publicOrgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: false})
|
publicOrgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: false})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, publicOrgUsers, 1)
|
assert.Len(t, publicOrgUsers, 1)
|
||||||
assert.Equal(t, *orgUsers[0], *publicOrgUsers[0])
|
assert.Equal(t, *orgUsers[1], *publicOrgUsers[0])
|
||||||
|
|
||||||
orgUsers, err = organization.GetOrgUsersByUserID(1, &organization.SearchOrganizationsOptions{All: true})
|
orgUsers, err = organization.GetOrgUsersByUserID(1, &organization.SearchOrganizationsOptions{All: true})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -92,33 +92,25 @@ func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
|
||||||
return perm.AccessModeNone, nil
|
return perm.AccessModeNone, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: ActionUser permission check
|
||||||
accessMode := perm.AccessModeNone
|
accessMode := perm.AccessModeNone
|
||||||
if ctx.Package.Owner.IsOrganization() {
|
if ctx.Package.Owner.IsOrganization() {
|
||||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||||
|
|
||||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||||
if ctx.Doer != nil {
|
// 1. If user is logged in, check all team packages permissions
|
||||||
var err error
|
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||||
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return accessMode, err
|
return accessMode, err
|
||||||
}
|
}
|
||||||
// If access mode is less than write check every team for more permissions
|
for _, t := range teams {
|
||||||
if accessMode < perm.AccessModeWrite {
|
perm := t.UnitAccessMode(ctx, unit.TypePackages)
|
||||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
if accessMode < perm {
|
||||||
if err != nil {
|
accessMode = perm
|
||||||
return accessMode, err
|
|
||||||
}
|
|
||||||
for _, t := range teams {
|
|
||||||
perm := t.UnitAccessMode(ctx, unit.TypePackages)
|
|
||||||
if accessMode < perm {
|
|
||||||
accessMode = perm
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||||
// 2. If authorize level is none, check if org is visible to user
|
// 2. If user is non-login, check if org is visible to non-login user
|
||||||
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
|
||||||
accessMode = perm.AccessModeRead
|
accessMode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -157,6 +157,7 @@ func TestPackageAccess(t *testing.T) {
|
||||||
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||||
inactive := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9})
|
inactive := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9})
|
||||||
|
privatedOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 23})
|
||||||
|
|
||||||
uploadPackage := func(doer, owner *user_model.User, expectedStatus int) {
|
uploadPackage := func(doer, owner *user_model.User, expectedStatus int) {
|
||||||
url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/file.bin", owner.Name)
|
url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/file.bin", owner.Name)
|
||||||
|
@ -170,6 +171,15 @@ func TestPackageAccess(t *testing.T) {
|
||||||
uploadPackage(inactive, user, http.StatusUnauthorized)
|
uploadPackage(inactive, user, http.StatusUnauthorized)
|
||||||
uploadPackage(admin, inactive, http.StatusCreated)
|
uploadPackage(admin, inactive, http.StatusCreated)
|
||||||
uploadPackage(admin, user, http.StatusCreated)
|
uploadPackage(admin, user, http.StatusCreated)
|
||||||
|
|
||||||
|
// team.authorize is write, but team_unit.access_mode is none
|
||||||
|
// so the user can not upload packages or get package list
|
||||||
|
uploadPackage(user, privatedOrg, http.StatusUnauthorized)
|
||||||
|
|
||||||
|
session := loginUser(t, user.Name)
|
||||||
|
tokenReadPackage := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadPackage)
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/packages/%s?token=%s", privatedOrg.Name, tokenReadPackage))
|
||||||
|
MakeRequest(t, req, http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPackageQuota(t *testing.T) {
|
func TestPackageQuota(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue