Skip to content

Commit

Permalink
fix: return 403 on restricted lambda call
Browse files Browse the repository at this point in the history
  • Loading branch information
reddec committed Jul 27, 2020
1 parent edbeb6c commit 074c8e0
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 31 deletions.
34 changes: 24 additions & 10 deletions application/adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ package application

import (
"context"
"github.com/reddec/trusted-cgi/stats"
"github.com/reddec/trusted-cgi/types"
"net/http"
"strings"
"time"

"github.com/reddec/trusted-cgi/stats"
"github.com/reddec/trusted-cgi/types"
)

// Expose lambda over HTTP handler. First part of path will be used as lambda UID
func HandlerByUID(globalCtx context.Context, tracker stats.Recorder, platform Platform) http.HandlerFunc {
return handler(globalCtx, platform, tracker, platform.FindByUID)
func HandlerByUID(globalCtx context.Context, policies Validator, tracker stats.Recorder, platform Platform) http.HandlerFunc {
return handler(globalCtx, policies, platform, tracker, platform.FindByUID)
}

// Expose lambda over HTTP handler. First part of path will be used as lambda alias
func HandlerByLinks(globalCtx context.Context, tracker stats.Recorder, platform Platform) http.HandlerFunc {
return handler(globalCtx, platform, tracker, platform.FindByLink)
func HandlerByLinks(globalCtx context.Context, policies Validator, tracker stats.Recorder, platform Platform) http.HandlerFunc {
return handler(globalCtx, policies, platform, tracker, platform.FindByLink)
}

// Expose queues over HTTP handler. First part of path will be used as queue name
Expand All @@ -25,16 +26,21 @@ func HandlerByQueues(queues Queues) http.HandlerFunc {
}

// Expose lambda handlers by UID (/a/) and by links (/l/) and for queues (/q/)
func Handler(globalCtx context.Context, tracker stats.Recorder, platform Platform, queues Queues) *http.ServeMux {
func Handler(globalCtx context.Context, policies Validator, tracker stats.Recorder, platform Platform, queues Queues) *http.ServeMux {
mux := http.NewServeMux()
mux.Handle("/a/", http.StripPrefix("/a/", HandlerByUID(globalCtx, tracker, platform)))
mux.Handle("/l/", http.StripPrefix("/l/", HandlerByLinks(globalCtx, tracker, platform)))
mux.Handle("/a/", http.StripPrefix("/a/", HandlerByUID(globalCtx, policies, tracker, platform)))
mux.Handle("/l/", http.StripPrefix("/l/", HandlerByLinks(globalCtx, policies, tracker, platform)))
mux.Handle("/q/", http.StripPrefix("/q/", HandlerByQueues(queues)))
//TODO: queue balancer
return mux
}

func handler(globalCtx context.Context, platform Platform, tracker stats.Recorder, lookup func(string) (*Definition, error)) http.HandlerFunc {
func handler(
globalCtx context.Context,
policies Validator,
platform Platform,
tracker stats.Recorder,
lookup func(string) (*Definition, error)) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
defer request.Body.Close()

Expand All @@ -56,6 +62,14 @@ func handler(globalCtx context.Context, platform Platform, tracker stats.Recorde
http.Error(writer, err.Error(), http.StatusNotFound)
return
}
err = policies.Inspect(uid, req)
if err != nil {
record.End = time.Now()
record.Err = err.Error()
tracker.Track(record)
http.Error(writer, err.Error(), http.StatusForbidden)
return
}
for k, v := range lambda.Lambda.Manifest().OutputHeaders {
writer.Header().Set(k, v)
}
Expand Down
74 changes: 66 additions & 8 deletions application/adapters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,42 @@ package application_test
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"

"github.com/google/uuid"

"github.com/reddec/trusted-cgi/application"
"github.com/reddec/trusted-cgi/application/lambda"
"github.com/reddec/trusted-cgi/application/platform"
"github.com/reddec/trusted-cgi/internal"
"github.com/reddec/trusted-cgi/stats/impl/memlog"
"github.com/reddec/trusted-cgi/types"

"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
)

type mockValidator struct {
forbidden map[string]error
}

func (mv *mockValidator) Inspect(lambda string, request *types.Request) error {
return mv.forbidden[lambda]
}

func TestHandlerByUID(t *testing.T) {
mc := &mockValidator{}
d, err := ioutil.TempDir("", "test-adapters-")
if !assert.NoError(t, err) {
return
}
defer os.RemoveAll(d)
base, err := platform.New(filepath.Join(d, internal.ProjectManifest))
base, err := platform.New(filepath.Join(d, internal.ProjectManifest), mc)
if !assert.NoError(t, err) {
return
}
Expand All @@ -45,7 +59,7 @@ func TestHandlerByUID(t *testing.T) {
return
}

handler := application.HandlerByUID(context.Background(), memlog.New(1), base)
handler := application.HandlerByUID(context.Background(), mc, memlog.New(1), base)

testServer := httptest.NewServer(handler)
url := testServer.URL + "/" + uid
Expand All @@ -62,3 +76,47 @@ func TestHandlerByUID(t *testing.T) {
}
assert.Equal(t, "hello world", string(data))
}

func TestHandlerByUID_forbidden(t *testing.T) {
mc := &mockValidator{
forbidden: map[string]error{},
}
d, err := ioutil.TempDir("", "test-adapters-")
if !assert.NoError(t, err) {
return
}
defer os.RemoveAll(d)
base, err := platform.New(filepath.Join(d, internal.ProjectManifest), mc)
if !assert.NoError(t, err) {
return
}
uid := uuid.New().String()
mc.forbidden[uid] = fmt.Errorf("not allowed")
lpath := filepath.Join(d, uid)
err = os.MkdirAll(lpath, 0755)
if !assert.NoError(t, err) {
return
}
t.Log("UID:", uid)

fn, err := lambda.DummyPublic(lpath, "/usr/bin/cat", "-")
if !assert.NoError(t, err) {
return
}
err = base.Add(uid, fn)
if !assert.NoError(t, err) {
return
}

handler := application.HandlerByUID(context.Background(), mc, memlog.New(1), base)

testServer := httptest.NewServer(handler)
url := testServer.URL + "/" + uid
t.Log("URL:", url)
res, err := testServer.Client().Post(url, "", bytes.NewBufferString("hello world"))
if !assert.NoError(t, err) {
return
}
defer res.Body.Close()
assert.Equal(t, http.StatusForbidden, res.StatusCode)
}
19 changes: 15 additions & 4 deletions application/platform/platform_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package platform_test

import (
"github.com/reddec/trusted-cgi/application/lambda"
"github.com/reddec/trusted-cgi/application/platform"
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"testing"

"github.com/reddec/trusted-cgi/application/lambda"
"github.com/reddec/trusted-cgi/application/platform"
"github.com/reddec/trusted-cgi/types"

"github.com/stretchr/testify/assert"
)

type mockValidator struct {
forbidden map[string]error
}

func (mv *mockValidator) Inspect(lambda string, request *types.Request) error {
return mv.forbidden[lambda]
}

func TestPlatform_AddWithOldAliases(t *testing.T) {
temp, err := ioutil.TempFile("", "")
if !assert.NoError(t, err) {
Expand All @@ -33,7 +44,7 @@ func TestPlatform_AddWithOldAliases(t *testing.T) {
return
}

plato, err := platform.New(temp.Name())
plato, err := platform.New(temp.Name(), &mockValidator{})
if !assert.NoError(t, err) {
return
}
Expand Down
14 changes: 8 additions & 6 deletions cmd/trusted-cgi/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"time"

"github.com/jessevdk/go-flags"

"github.com/reddec/trusted-cgi/api/services"
"github.com/reddec/trusted-cgi/application"
"github.com/reddec/trusted-cgi/application/cases"
Expand All @@ -17,11 +24,6 @@ import (
"github.com/reddec/trusted-cgi/queue/inmemory"
"github.com/reddec/trusted-cgi/server"
"github.com/reddec/trusted-cgi/stats/impl/memlog"
"log"
"net/http"
"os"
"path/filepath"
"time"
)

const version = "dev"
Expand Down Expand Up @@ -177,7 +179,7 @@ func run(ctx context.Context, config Config) error {
defer tracker.Dump()
go dumpTracker(ctx, config.StatsInterval, tracker)

handler, err := server.Handler(ctx, config.Dev, basePlatform, queueManager, tracker, userApi, projectApi, lambdaApi, userApi, queuesApi, policiesApi)
handler, err := server.Handler(ctx, config.Dev, policies, basePlatform, queueManager, tracker, userApi, projectApi, lambdaApi, userApi, queuesApi, policiesApi)
if err != nil {
return err
}
Expand Down
9 changes: 6 additions & 3 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package server

import (
"context"
"net/http"

"github.com/reddec/jsonrpc2"

"github.com/reddec/trusted-cgi/api"
"github.com/reddec/trusted-cgi/api/handlers"
"github.com/reddec/trusted-cgi/application"
"github.com/reddec/trusted-cgi/assets"
"github.com/reddec/trusted-cgi/stats"
"net/http"
)

func Handler(ctx context.Context,
dev bool,
policies application.Validator,
platform application.Platform,
queues application.Queues,
tracker stats.Stats,
Expand All @@ -27,8 +30,8 @@ func Handler(ctx context.Context,
) (http.Handler, error) {
var mux http.ServeMux
// main API
apps := application.HandlerByUID(ctx, tracker, platform)
links := application.HandlerByLinks(ctx, tracker, platform)
apps := application.HandlerByUID(ctx, policies, tracker, platform)
links := application.HandlerByLinks(ctx, policies, tracker, platform)
queuesHandler := application.HandlerByQueues(queues)

mux.Handle("/a/", openedHandler(http.StripPrefix("/a/", apps)))
Expand Down

0 comments on commit 074c8e0

Please sign in to comment.