From e8af871f988ab5f3857e007b8f3355478e2b11a7 Mon Sep 17 00:00:00 2001 From: harryzcy Date: Tue, 1 Nov 2022 01:23:17 -0400 Subject: [PATCH] Limit scope for `/api/v1/orgs` --- routers/api/v1/api.go | 50 ++++++++++----------- tests/integration/api_issue_label_test.go | 2 +- tests/integration/api_org_test.go | 20 +++++---- tests/integration/api_repo_test.go | 2 +- tests/integration/api_team_test.go | 8 ++-- tests/integration/api_user_org_perm_test.go | 6 +-- tests/integration/api_user_orgs_test.go | 4 +- tests/integration/org_count_test.go | 2 +- tests/integration/org_test.go | 2 +- 9 files changed, 50 insertions(+), 46 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 2a84c59ebc..cf7d1f3b41 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1103,41 +1103,41 @@ func Routes(ctx gocontext.Context) *web.Route { }, context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead)) // Organizations - m.Get("/user/orgs", reqToken(""), org.ListMyOrgs) + m.Get("/user/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMyOrgs) m.Group("/users/{username}/orgs", func() { - m.Get("", org.ListUserOrgs) - m.Get("/{org}/permissions", reqToken(""), org.GetUserOrgsPermissions) + m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListUserOrgs) + m.Get("/{org}/permissions", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetUserOrgsPermissions) }, context_service.UserAssignmentAPI()) - m.Post("/orgs", reqToken(""), bind(api.CreateOrgOption{}), org.Create) - m.Get("/orgs", org.GetAll) + m.Post("/orgs", reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateOrgOption{}), org.Create) + m.Get("/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetAll) m.Group("/orgs/{org}", func() { - m.Combo("").Get(org.Get). - Patch(reqToken(""), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit). - Delete(reqToken(""), reqOrgOwnership(), org.Delete) - m.Combo("/repos").Get(user.ListOrgRepos). - Post(reqToken(""), bind(api.CreateRepoOption{}), repo.CreateOrgRepo) + m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.Get). + Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit). + Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.Delete) + m.Combo("/repos").Get(reqToken(auth_model.AccessTokenScopeReadOrg), user.ListOrgRepos). + Post(reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepo) m.Group("/members", func() { - m.Get("", org.ListMembers) - m.Combo("/{username}").Get(org.IsMember). - Delete(reqToken(""), reqOrgOwnership(), org.DeleteMember) + m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMembers) + m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsMember). + Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteMember) }) m.Group("/public_members", func() { - m.Get("", org.ListPublicMembers) - m.Combo("/{username}").Get(org.IsPublicMember). - Put(reqToken(""), reqOrgMembership(), org.PublicizeMember). - Delete(reqToken(""), reqOrgMembership(), org.ConcealMember) + m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListPublicMembers) + m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsPublicMember). + Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.PublicizeMember). + Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.ConcealMember) }) m.Group("/teams", func() { - m.Get("", org.ListTeams) + m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListTeams) m.Post("", reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam) m.Get("/search", org.SearchTeam) - }, reqToken(""), reqOrgMembership()) + }, reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership()) m.Group("/labels", func() { - m.Get("", org.ListLabels) - m.Post("", reqToken(""), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel) - m.Combo("/{id}").Get(org.GetLabel). - Patch(reqToken(""), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel). - Delete(reqToken(""), reqOrgOwnership(), org.DeleteLabel) + m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListLabels) + m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel) + m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetLabel). + Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel). + Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteLabel) }) m.Group("/hooks", func() { m.Combo("").Get(org.ListHooks). @@ -1145,7 +1145,7 @@ func Routes(ctx gocontext.Context) *web.Route { m.Combo("/{id}").Get(org.GetHook). Patch(bind(api.EditHookOption{}), org.EditHook). Delete(org.DeleteHook) - }, reqToken(""), reqOrgOwnership(), reqWebhooksEnabled()) + }, reqToken(auth_model.AccessTokenScopeAdminOrgHook), reqOrgOwnership(), reqWebhooksEnabled()) }, orgAssignment(true)) m.Group("/teams/{teamid}", func() { m.Combo("").Get(org.GetTeam). diff --git a/tests/integration/api_issue_label_test.go b/tests/integration/api_issue_label_test.go index 378ed73817..b4c96e3838 100644 --- a/tests/integration/api_issue_label_test.go +++ b/tests/integration/api_issue_label_test.go @@ -144,7 +144,7 @@ func TestAPIModifyOrgLabels(t *testing.T) { owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) user := "user1" session := loginUser(t, user) - token := getTokenForLoggedInUser(t, session, "repo") + token := getTokenForLoggedInUser(t, session, "repo", "admin_org") urlStr := fmt.Sprintf("/api/v1/orgs/%s/labels?token=%s", owner.Name, token) // CreateLabel diff --git a/tests/integration/api_org_test.go b/tests/integration/api_org_test.go index 16e53d6b81..67902f8550 100644 --- a/tests/integration/api_org_test.go +++ b/tests/integration/api_org_test.go @@ -22,7 +22,7 @@ import ( func TestAPIOrgCreate(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { - token := getUserToken(t, "user1") + token := getUserToken(t, "user1", "write_org", "read_org") org := api.CreateOrgOption{ UserName: "user1_org", @@ -80,7 +80,7 @@ func TestAPIOrgEdit(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "write_org") org := api.EditOrgOption{ FullName: "User3 organization new full name", Description: "A new description", @@ -107,7 +107,7 @@ func TestAPIOrgEditBadVisibility(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "write_org") org := api.EditOrgOption{ FullName: "User3 organization new full name", Description: "A new description", @@ -127,14 +127,16 @@ func TestAPIOrgDeny(t *testing.T) { setting.Service.RequireSignInView = false }() + token := getUserToken(t, "user1", "read_org") + orgName := "user1_org" - req := NewRequestf(t, "GET", "/api/v1/orgs/%s", orgName) + req := NewRequestf(t, "GET", "/api/v1/orgs/%s?token=%s", orgName, token) MakeRequest(t, req, http.StatusNotFound) - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", orgName) + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token=%s", orgName, token) MakeRequest(t, req, http.StatusNotFound) - req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members", orgName) + req = NewRequestf(t, "GET", "/api/v1/orgs/%s/members?token=%s", orgName, token) MakeRequest(t, req, http.StatusNotFound) }) } @@ -142,7 +144,9 @@ func TestAPIOrgDeny(t *testing.T) { func TestAPIGetAll(t *testing.T) { defer tests.PrepareTestEnv(t)() - req := NewRequestf(t, "GET", "/api/v1/orgs") + token := getUserToken(t, "user1", "read_org") + + req := NewRequestf(t, "GET", "/api/v1/orgs?token=%s", token) resp := MakeRequest(t, req, http.StatusOK) var apiOrgList []*api.Organization @@ -155,7 +159,7 @@ func TestAPIGetAll(t *testing.T) { func TestAPIOrgSearchEmptyTeam(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { - token := getUserToken(t, "user1") + token := getUserToken(t, "user1", "admin_org") orgName := "org_with_empty_team" // create org diff --git a/tests/integration/api_repo_test.go b/tests/integration/api_repo_test.go index a71c26926e..7e9e899799 100644 --- a/tests/integration/api_repo_test.go +++ b/tests/integration/api_repo_test.go @@ -300,7 +300,7 @@ func TestAPIOrgRepos(t *testing.T) { if userToLogin != nil && userToLogin.ID > 0 { testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID) session = loginUser(t, userToLogin.Name) - token = getTokenForLoggedInUser(t, session) + token = getTokenForLoggedInUser(t, session, "read_org") } else { testName = "AnonymousUser" session = emptyTestSession(t) diff --git a/tests/integration/api_team_test.go b/tests/integration/api_team_test.go index a667949c09..8ba350adc2 100644 --- a/tests/integration/api_team_test.go +++ b/tests/integration/api_team_test.go @@ -30,7 +30,7 @@ func TestAPITeam(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID}) session := loginUser(t, user.Name) - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "admin_org") req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID) resp := session.MakeRequest(t, req, http.StatusOK) @@ -228,7 +228,7 @@ func TestAPITeamSearch(t *testing.T) { var results TeamSearchResults - token := getUserToken(t, user.Name) + token := getUserToken(t, user.Name, "read_org") req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "_team", token) resp := MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &results) @@ -253,7 +253,7 @@ func TestAPIGetTeamRepo(t *testing.T) { var results api.Repository - token := getUserToken(t, user.Name) + token := getUserToken(t, user.Name, "read_org") req := NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/?token=%s", team.ID, teamRepo.FullName(), token) resp := MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &results) @@ -261,7 +261,7 @@ func TestAPIGetTeamRepo(t *testing.T) { // no access if not organization member user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) - token5 := getUserToken(t, user5.Name) + token5 := getUserToken(t, user5.Name, "read_org") req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/?token=%s", team.ID, teamRepo.FullName(), token5) MakeRequest(t, req, http.StatusNotFound) diff --git a/tests/integration/api_user_org_perm_test.go b/tests/integration/api_user_org_perm_test.go index fef653545c..e083cce7d3 100644 --- a/tests/integration/api_user_org_perm_test.go +++ b/tests/integration/api_user_org_perm_test.go @@ -34,7 +34,7 @@ func sampleTest(t *testing.T, auoptc apiUserOrgPermTestCase) { defer tests.PrepareTestEnv(t)() session := loginUser(t, auoptc.LoginUser) - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "read_org") req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/%s/orgs/%s/permissions?token=%s", auoptc.User, auoptc.Organization, token)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -127,7 +127,7 @@ func TestUnknowUser(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "read_org") req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/unknow/orgs/org25/permissions?token=%s", token)) resp := session.MakeRequest(t, req, http.StatusNotFound) @@ -141,7 +141,7 @@ func TestUnknowOrganization(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "read_org") req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/users/user1/orgs/unknow/permissions?token=%s", token)) resp := session.MakeRequest(t, req, http.StatusNotFound) diff --git a/tests/integration/api_user_orgs_test.go b/tests/integration/api_user_orgs_test.go index c28bf391eb..93a3c9c047 100644 --- a/tests/integration/api_user_orgs_test.go +++ b/tests/integration/api_user_orgs_test.go @@ -72,7 +72,7 @@ func getUserOrgs(t *testing.T, userDoer, userCheck string) (orgs []*api.Organiza session := emptyTestSession(t) if len(userDoer) != 0 { session = loginUser(t, userDoer) - token = getTokenForLoggedInUser(t, session) + token = getTokenForLoggedInUser(t, session, "read_org") } urlStr := fmt.Sprintf("/api/v1/users/%s/orgs?token=%s", userCheck, token) req := NewRequest(t, "GET", urlStr) @@ -90,7 +90,7 @@ func TestMyOrgs(t *testing.T) { normalUsername := "user2" session = loginUser(t, normalUsername) - token := getTokenForLoggedInUser(t, session) + token := getTokenForLoggedInUser(t, session, "read_org") req = NewRequest(t, "GET", "/api/v1/user/orgs?token="+token) resp := session.MakeRequest(t, req, http.StatusOK) var orgs []*api.Organization diff --git a/tests/integration/org_count_test.go b/tests/integration/org_count_test.go index 96f39924f1..6c15ec79b7 100644 --- a/tests/integration/org_count_test.go +++ b/tests/integration/org_count_test.go @@ -25,7 +25,7 @@ func testOrgCounts(t *testing.T, u *url.URL) { orgOwner := "user2" orgName := "testOrg" orgCollaborator := "user4" - ctx := NewAPITestContext(t, orgOwner, "repo1") + ctx := NewAPITestContext(t, orgOwner, "repo1", "admin_org") var ownerCountRepos map[string]int var collabCountRepos map[string]int diff --git a/tests/integration/org_test.go b/tests/integration/org_test.go index d04fcf7f57..91cab00e47 100644 --- a/tests/integration/org_test.go +++ b/tests/integration/org_test.go @@ -159,7 +159,7 @@ func TestOrgRestrictedUser(t *testing.T) { // Therefore create a read-only team adminSession := loginUser(t, "user1") - token := getTokenForLoggedInUser(t, adminSession) + token := getTokenForLoggedInUser(t, adminSession, "admin_org") teamToCreate := &api.CreateTeamOption{ Name: "codereader",