Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict permission check on repositories and fix some problems #5314

Merged
merged 32 commits into from
Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0bf41c2
fix units permission problems
lunny Nov 10, 2018
15f80b9
fix some bugs and merge LoadUnits to repoAssignment
lunny Nov 11, 2018
40d552c
refactor permission struct and add some copyright heads
lunny Nov 11, 2018
d80fea2
remove unused codes
lunny Nov 11, 2018
fb4a2cb
fix routes units check
lunny Nov 11, 2018
a21bfde
improve permission check
lunny Nov 11, 2018
422ba40
add unit tests for permission
lunny Nov 12, 2018
dae595b
fix typo
lunny Nov 12, 2018
6bed0d4
fix tests
lunny Nov 12, 2018
d5ba3a0
fix some routes
lunny Nov 12, 2018
426980d
fix api permission check
lunny Nov 12, 2018
50d1287
improve permission check
lunny Nov 12, 2018
95d9a58
fix some permission check
lunny Nov 13, 2018
5df61b6
fix tests
lunny Nov 13, 2018
4ee6e1f
fix tests
lunny Nov 13, 2018
de04377
improve some permission check
lunny Nov 13, 2018
66fd8f3
fix some permission check
lunny Nov 14, 2018
11bde94
refactor AccessLevel
lunny Nov 17, 2018
ba60cc8
fix bug
lunny Nov 17, 2018
a978acc
fix tests
lunny Nov 17, 2018
d161315
fix tests
lunny Nov 17, 2018
e5e165c
fix tests
lunny Nov 17, 2018
9253015
fix AccessLevel
lunny Nov 18, 2018
2f65f7a
rename CanAccess
lunny Nov 18, 2018
962be78
fix tests
lunny Nov 18, 2018
9742d63
fix comment
lunny Nov 18, 2018
2db05db
fix bug
lunny Nov 18, 2018
3620109
add missing unit for test repos
lunny Nov 18, 2018
861b3b2
fix bug
lunny Nov 18, 2018
b677d04
rename some functions
lunny Nov 18, 2018
79365d8
fix routes check
lunny Nov 18, 2018
d54bc51
Merge branch 'master' into lunny/fix_units_permissions
lunny Nov 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix some permission check
  • Loading branch information
lunny committed Nov 28, 2018
commit 66fd8f33dcea1dcc4ffa722f8a97334f35d9c9d6
12 changes: 9 additions & 3 deletions models/branches.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,16 @@ func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6

whitelist = make([]int64, 0, len(newWhitelist))
for _, userID := range newWhitelist {
has, err := hasAccess(x, userID, repo, AccessModeWrite)
user, err := GetUserByID(userID)
if err != nil {
return nil, fmt.Errorf("HasAccess [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
} else if !has {
return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
}
perm, err := GetUserRepoPermission(repo, user)
if err != nil {
return nil, fmt.Errorf("GetUserRepoPermission [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
}

if !perm.CanWrite(UnitTypeCode) {
continue // Drop invalid user ID
}

Expand Down
12 changes: 8 additions & 4 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,11 @@ func (issue *Issue) RemoveLabel(doer *User, label *Label) error {
return err
}

if has, err := HasAccess(doer.ID, issue.Repo, AccessModeWrite); err != nil {
perm, err := GetUserRepoPermission(issue.Repo, doer)
if err != nil {
return err
} else if !has {
}
if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
return ErrLabelNotExist{}
}

Expand Down Expand Up @@ -511,9 +513,11 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
return err
}

if has, err := hasAccess(sess, doer.ID, issue.Repo, AccessModeWrite); err != nil {
perm, err := getUserRepoPermission(sess, issue.Repo, doer)
if err != nil {
return err
} else if !has {
}
if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
return ErrLabelNotExist{}
}

Expand Down
5 changes: 3 additions & 2 deletions models/lfs_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,11 @@ func CheckLFSAccessForRepo(u *User, repo *Repository, mode AccessMode) error {
if u == nil {
return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode}
}
has, err := HasAccess(u.ID, repo, mode)
perm, err := GetUserRepoPermission(repo, u)
if err != nil {
return err
} else if !has {
}
if !perm.CanWrite(UnitTypeCode) {
return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode}
}
return nil
Expand Down
9 changes: 2 additions & 7 deletions models/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,11 +553,6 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) {
return repo.getAssignees(x)
}

// GetUserIfHasWriteAccess returns the user that has write access of repository by given ID.
func (repo *Repository) GetUserIfHasWriteAccess(userID int64) (*User, error) {
return GetUserIfHasWriteAccess(repo, userID)
}

// GetMilestoneByID returns the milestone belongs to repository by given ID.
func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error) {
return GetMilestoneByRepoID(repo.ID, milestoneID)
Expand Down Expand Up @@ -625,10 +620,10 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
}

// HasAccess returns true when user has access to this repository
func (repo *Repository) HasAccess(u *User) bool {
/*func (repo *Repository) HasAccess(u *User) bool {
has, _ := HasAccess(u.ID, repo, AccessModeRead)
return has
}
}*/

// UpdateDefaultBranch updates the default branch
func (repo *Repository) UpdateDefaultBranch() error {
Expand Down
20 changes: 20 additions & 0 deletions models/repo_permission.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,23 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss

return
}

// IsUserRepoAdmin return ture if user has admin right of a repo
func IsUserRepoAdmin(repo *Repository, user *User) (bool, error) {
return isUserRepoAdmin(x, repo, user)
}

func isUserRepoAdmin(e Engine, repo *Repository, user *User) (bool, error) {
if user == nil || repo == nil {
return false, nil
}
if user.IsAdmin {
return true, nil
}

mode, err := accessLevel(e, user.ID, repo)
if err != nil {
return false, err
}
return mode >= AccessModeAdmin, nil
}
6 changes: 3 additions & 3 deletions models/ssh_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,10 +807,10 @@ func DeleteDeployKey(doer *User, id int64) error {
if err != nil {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
yes, err := HasAccess(doer.ID, repo, AccessModeAdmin)
has, err := IsUserRepoAdmin(repo, doer)
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !yes {
return fmt.Errorf("GetUserRepoPermission: %v", err)
} else if !has {
return ErrKeyAccessDenied{doer.ID, key.ID, "deploy"}
}
}
Expand Down
29 changes: 0 additions & 29 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,24 +496,6 @@ func (u *User) DeleteAvatar() error {
return nil
}

// IsAdminOfRepo returns true if user has admin or higher access of repository.
func (u *User) IsAdminOfRepo(repo *Repository) bool {
has, err := HasAccess(u.ID, repo, AccessModeAdmin)
if err != nil {
log.Error(3, "HasAccess: %v", err)
}
return has
}

// IsWriterOfRepo returns true if user has write access to given repository.
func (u *User) IsWriterOfRepo(repo *Repository) bool {
has, err := HasAccess(u.ID, repo, AccessModeWrite)
if err != nil {
log.Error(3, "HasAccess: %v", err)
}
return has
}

// IsOrganization returns true if user is actually a organization.
func (u *User) IsOrganization() bool {
return u.Type == UserTypeOrganization
Expand Down Expand Up @@ -1170,17 +1152,6 @@ func GetUserByID(id int64) (*User, error) {
return getUserByID(x, id)
}

// GetUserIfHasWriteAccess returns the user with write access of repository by given ID.
func GetUserIfHasWriteAccess(repo *Repository, userID int64) (*User, error) {
has, err := HasAccess(userID, repo, AccessModeWrite)
if err != nil {
return nil, err
} else if !has {
return nil, ErrUserNotExist{userID, "", 0}
}
return GetUserByID(userID)
}

// GetUserByName returns user by given name.
func GetUserByName(name string) (*User, error) {
return getUserByName(x, name)
Expand Down
15 changes: 9 additions & 6 deletions modules/lfs/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,12 +497,12 @@ func authenticate(ctx *context.Context, repository *models.Repository, authoriza
accessMode = models.AccessModeWrite
}

if !repository.IsPrivate && !requireWrite {
return true
perm, err := models.GetUserRepoPermission(repository, ctx.User)
if err != nil {
return false
}
if ctx.IsSigned {
accessCheck, _ := models.HasAccess(ctx.User.ID, repository, accessMode)
return accessCheck
return perm.UnitAccessMode(models.UnitTypeCode) >= accessMode
}

user, repo, opStr, err := parseToken(authorization)
Expand All @@ -511,8 +511,11 @@ func authenticate(ctx *context.Context, repository *models.Repository, authoriza
}
ctx.User = user
if opStr == "basic" {
accessCheck, _ := models.HasAccess(ctx.User.ID, repository, accessMode)
return accessCheck
perm, err = models.GetUserRepoPermission(repository, ctx.User)
if err != nil {
return false
}
return perm.UnitAccessMode(models.UnitTypeCode) >= accessMode
}
if repository.ID == repo.ID {
if requireWrite && opStr != "upload" {
Expand Down
7 changes: 6 additions & 1 deletion routers/api/v1/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,12 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
}
}

if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
perm, err := models.GetUserRepoPermission(headRepo, ctx.User)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return nil, nil, nil, nil, "", ""
}
if !perm.CanWrite(models.UnitTypeCode) {
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
ctx.Status(404)
return nil, nil, nil, nil, "", ""
Expand Down
107 changes: 61 additions & 46 deletions routers/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ func NewIssue(ctx *context.Context) {
}

// ValidateRepoMetas check and returns repository's meta informations
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, []int64, int64) {
func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull bool) ([]int64, []int64, int64) {
var (
repo = ctx.Repo.Repository
err error
Expand Down Expand Up @@ -428,9 +428,19 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64

// Check if the passed assignees actually exists and has write access to the repo
for _, aID := range assigneeIDs {
_, err = repo.GetUserIfHasWriteAccess(aID)
user, err := models.GetUserByID(aID)
if err != nil {
ctx.ServerError("GetUserIfHasWriteAccess", err)
ctx.ServerError("GetUserByID", err)
return nil, nil, 0
}

perm, err := models.GetUserRepoPermission(repo, user)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return nil, nil, 0
}
if !perm.CanWriteIssuesOrPulls(isPull) {
ctx.ServerError("CanWriteIssuesOrPulls", fmt.Errorf("No permission for %s", user.Name))
return nil, nil, 0
}
}
Expand Down Expand Up @@ -459,7 +469,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
attachments []string
)

labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form)
labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form, false)
if ctx.Written() {
return
}
Expand Down Expand Up @@ -499,31 +509,23 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {

// commentTag returns the CommentTag for a comment in/with the given repo, poster and issue
func commentTag(repo *models.Repository, poster *models.User, issue *models.Issue) (models.CommentTag, error) {
if repo.IsOwnedBy(poster.ID) {
return models.CommentTagOwner, nil
} else if repo.Owner.IsOrganization() {
isOwner, err := repo.Owner.IsOwnedBy(poster.ID)
if err != nil {
return models.CommentTagNone, err
} else if isOwner {
return models.CommentTagOwner, nil
}
perm, err := models.GetUserRepoPermission(repo, poster)
if err != nil {
return models.CommentTagNone, err
}
if poster.IsWriterOfRepo(repo) {
return models.CommentTagWriter, nil
if perm.IsOwner() {
return models.CommentTagOwner, nil
} else if poster.ID == issue.PosterID {
return models.CommentTagPoster, nil
} else if perm.CanWrite(models.UnitTypeCode) {
return models.CommentTagWriter, nil
}

return models.CommentTagNone, nil
}

// ViewIssue render issue view page
func ViewIssue(ctx *context.Context) {
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireDropzone"] = true
ctx.Data["RequireTribute"] = true
renderAttachmentSettings(ctx)

issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
Expand All @@ -533,25 +535,6 @@ func ViewIssue(ctx *context.Context) {
}
return
}
ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)

var iw *models.IssueWatch
var exists bool
if ctx.User != nil {
iw, exists, err = models.GetIssueWatch(ctx.User.ID, issue.ID)
if err != nil {
ctx.ServerError("GetIssueWatch", err)
return
}
if !exists {
iw = &models.IssueWatch{
UserID: ctx.User.ID,
IssueID: issue.ID,
IsWatching: models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID),
}
}
}
ctx.Data["IssueWatch"] = iw

// Make sure type and URL matches.
if ctx.Params(":type") == "issues" && issue.IsPull {
Expand All @@ -577,6 +560,31 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["PageIsIssueList"] = true
}

ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireDropzone"] = true
ctx.Data["RequireTribute"] = true
renderAttachmentSettings(ctx)

ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)

var iw *models.IssueWatch
var exists bool
if ctx.User != nil {
iw, exists, err = models.GetIssueWatch(ctx.User.ID, issue.ID)
if err != nil {
ctx.ServerError("GetIssueWatch", err)
return
}
if !exists {
iw = &models.IssueWatch{
UserID: ctx.User.ID,
IssueID: issue.ID,
IsWatching: models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID),
}
}
}
ctx.Data["IssueWatch"] = iw

issue.RenderedContent = string(markdown.Render([]byte(issue.Content), ctx.Repo.RepoLink,
ctx.Repo.Repository.ComposeMetas()))

Expand Down Expand Up @@ -762,13 +770,20 @@ func ViewIssue(ctx *context.Context) {
if ctx.IsSigned {
if err := pull.GetHeadRepo(); err != nil {
log.Error(4, "GetHeadRepo: %v", err)
} else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch && ctx.User.IsWriterOfRepo(pull.HeadRepo) {
// Check if branch is not protected
if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch, ctx.User); err != nil {
log.Error(4, "IsProtectedBranch: %v", err)
} else if !protected {
canDelete = true
ctx.Data["DeleteBranchLink"] = ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index) + "/cleanup"
} else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch {
perm, err := models.GetUserRepoPermission(pull.HeadRepo, ctx.User)
if err != nil {
ctx.ServerError("GetUserRepoPermission", err)
return
}
if perm.CanWrite(models.UnitTypeCode) {
// Check if branch is not protected
if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch, ctx.User); err != nil {
log.Error(4, "IsProtectedBranch: %v", err)
} else if !protected {
canDelete = true
ctx.Data["DeleteBranchLink"] = ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index) + "/cleanup"
}
}
}
}
Expand Down
Loading