cloudapi: handle multi-tenancy in all compose/<id> endpoints

Use the `EnsureJobChannel()` middleware in all `compose/<id>` endpoints.
Specifically in the:
 - status
 - metadata
 - manifests
 - logs

As a result, these endpoints now return `404` in case the server has JWT
enabled and the channel associated with the request does not match the
channel associated with the requested compose (job).

Extend the multi-tenancy unit test to ensure that these endpoints behave
as expected in case of match and mismatch between the request and
compose channels.
This commit is contained in:
Tomas Hozza 2022-06-06 09:21:29 +02:00 committed by Tom Gundersen
parent fc7d090498
commit 4a94b46f33
2 changed files with 57 additions and 0 deletions

View file

@ -492,6 +492,10 @@ func imageTypeFromApiImageType(it ImageTypes, arch distro.Arch) string {
}
func (h *apiHandlers) GetComposeStatus(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeStatusImpl)(ctx, id)
}
func (h *apiHandlers) getComposeStatusImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
@ -738,6 +742,10 @@ func composeStatusFromKojiJobStatus(js *worker.JobStatus, initResult *worker.Koj
// ComposeMetadata handles a /composes/{id}/metadata GET request
func (h *apiHandlers) GetComposeMetadata(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeMetadataImpl)(ctx, id)
}
func (h *apiHandlers) getComposeMetadataImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
@ -849,6 +857,11 @@ func stagesToPackageMetadata(stages []osbuild.RPMStageMetadata) []PackageMetadat
// Get logs for a compose
func (h *apiHandlers) GetComposeLogs(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeLogsImpl)(ctx, id)
}
func (h *apiHandlers) getComposeLogsImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)
@ -959,6 +972,10 @@ func manifestJobResultsFromJobDeps(w *worker.Server, deps []uuid.UUID) (*worker.
// GetComposeIdManifests returns the Manifests for a given Compose (one for each image).
func (h *apiHandlers) GetComposeManifests(ctx echo.Context, id string) error {
return h.server.EnsureJobChannel(h.getComposeManifestsImpl)(ctx, id)
}
func (h *apiHandlers) getComposeManifestsImpl(ctx echo.Context, id string) error {
jobId, err := uuid.Parse(id)
if err != nil {
return HTTPError(ErrorInvalidComposeId)

View file

@ -276,5 +276,45 @@ func TestMultitenancy(t *testing.T) {
}
require.NoError(t, json.Unmarshal(resp.Body, &result))
require.NotEqual(t, "pending", result.Status)
composeEndpoints := []string{"", "logs", "manifests", "metadata"}
// Verify that all compose endpoints work with the appropriate orgID
for _, endpoint := range composeEndpoints {
// TODO: "metadata" endpoint is not supported for Koji composes
jobType, err := workerServer.JobType(c.id)
require.NoError(t, err)
if jobType == worker.JobTypeKojiFinalize && endpoint == "metadata" {
continue
}
path := "/api/image-builder-composer/v2/composes/" + c.id.String()
if endpoint != "" {
path = path + "/" + endpoint
}
_ = test.APICall{
Handler: handler,
Method: http.MethodGet,
Context: reqContext(c.orgID),
Path: path,
ExpectedStatus: http.StatusOK,
}.Do(t)
}
// Verify that no compose endpoints are accessible with wrong orgID
for _, endpoint := range composeEndpoints {
path := "/api/image-builder-composer/v2/composes/" + c.id.String()
if endpoint != "" {
path = path + "/" + endpoint
}
_ = test.APICall{
Handler: handler,
Method: http.MethodGet,
Context: reqContext("bad-org"),
Path: path,
ExpectedStatus: http.StatusNotFound,
}.Do(t)
}
}
}