From d85e36829f3f8259d7f76cdd5716464c6cb90fc5 Mon Sep 17 00:00:00 2001
From: KN4CK3R <admin@oldschoolhack.me>
Date: Mon, 24 Oct 2022 21:23:25 +0200
Subject: [PATCH] Fix package access for admins and inactive users (#21580)

I noticed an admin is not allowed to upload packages for other users
because `ctx.IsSigned` was not set.
I added a check for `user.IsActive` and `user.ProhibitLogin` too because
both was not checked. Tests enforce this now.

Co-authored-by: Lauris BH <lauris@nix.lv>
---
 integrations/api_packages_container_test.go |  4 ++++
 integrations/api_packages_test.go           | 22 +++++++++++++++++++++
 modules/context/package.go                  |  9 ++++++---
 routers/api/packages/api.go                 |  2 ++
 4 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/integrations/api_packages_container_test.go b/integrations/api_packages_container_test.go
index af659363d595a..ad987a662e979 100644
--- a/integrations/api_packages_container_test.go
+++ b/integrations/api_packages_container_test.go
@@ -433,6 +433,10 @@ func TestPackageContainer(t *testing.T) {
 
 				assert.Equal(t, fmt.Sprintf("%d", len(blobContent)), resp.Header().Get("Content-Length"))
 				assert.Equal(t, blobDigest, resp.Header().Get("Docker-Content-Digest"))
+
+				req = NewRequest(t, "HEAD", fmt.Sprintf("%s/blobs/%s", url, blobDigest))
+				addTokenAuthHeader(req, anonymousToken)
+				MakeRequest(t, req, http.StatusOK)
 			})
 
 			t.Run("GetBlob", func(t *testing.T) {
diff --git a/integrations/api_packages_test.go b/integrations/api_packages_test.go
index 1f24807060df7..5b871cd476ec0 100644
--- a/integrations/api_packages_test.go
+++ b/integrations/api_packages_test.go
@@ -24,6 +24,7 @@ import (
 
 func TestPackageAPI(t *testing.T) {
 	defer prepareTestEnv(t)()
+
 	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
 	session := loginUser(t, user.Name)
 	token := getTokenForLoggedInUser(t, session)
@@ -143,6 +144,27 @@ func TestPackageAPI(t *testing.T) {
 	})
 }
 
+func TestPackageAccess(t *testing.T) {
+	defer prepareTestEnv(t)()
+
+	admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
+	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
+	inactive := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 9}).(*user_model.User)
+
+	uploadPackage := func(doer, owner *user_model.User, expectedStatus int) {
+		url := fmt.Sprintf("/api/packages/%s/generic/test-package/1.0/file.bin", owner.Name)
+		req := NewRequestWithBody(t, "PUT", url, bytes.NewReader([]byte{1}))
+		AddBasicAuthHeader(req, doer.Name)
+		MakeRequest(t, req, expectedStatus)
+	}
+
+	uploadPackage(user, inactive, http.StatusUnauthorized)
+	uploadPackage(inactive, inactive, http.StatusUnauthorized)
+	uploadPackage(inactive, user, http.StatusUnauthorized)
+	uploadPackage(admin, inactive, http.StatusCreated)
+	uploadPackage(admin, user, http.StatusCreated)
+}
+
 func TestPackageCleanup(t *testing.T) {
 	defer prepareTestEnv(t)()
 
diff --git a/modules/context/package.go b/modules/context/package.go
index 89a8c4466c154..5ccea9ee9b7ef 100644
--- a/modules/context/package.go
+++ b/modules/context/package.go
@@ -83,12 +83,15 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
 }
 
 func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
-	accessMode := perm.AccessModeNone
-
 	if setting.Service.RequireSignInView && ctx.Doer == nil {
-		return accessMode, nil
+		return perm.AccessModeNone, nil
 	}
 
+	if ctx.Doer != nil && !ctx.Doer.IsGhost() && (!ctx.Doer.IsActive || ctx.Doer.ProhibitLogin) {
+		return perm.AccessModeNone, nil
+	}
+
+	accessMode := perm.AccessModeNone
 	if ctx.Package.Owner.IsOrganization() {
 		org := organization.OrgFromUser(ctx.Package.Owner)
 
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 96924698a3c10..0df6012b566b7 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -55,6 +55,7 @@ func Routes() *web.Route {
 	authGroup := auth.NewGroup(authMethods...)
 	r.Use(func(ctx *context.Context) {
 		ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
+		ctx.IsSigned = ctx.Doer != nil
 	})
 
 	r.Group("/{username}", func() {
@@ -256,6 +257,7 @@ func ContainerRoutes() *web.Route {
 	authGroup := auth.NewGroup(authMethods...)
 	r.Use(func(ctx *context.Context) {
 		ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
+		ctx.IsSigned = ctx.Doer != nil
 	})
 
 	r.Get("", container.ReqContainerAccess, container.DetermineSupport)