Skip to content

Commit

Permalink
Merge pull request #270 from Security-Onion-Solutions/cogburn/import-…
Browse files Browse the repository at this point in the history
…auth

Add AuthCheck to Import
  • Loading branch information
coreyogburn authored Aug 1, 2023
2 parents 846f575 + d9b1b07 commit e335d26
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 18 deletions.
2 changes: 1 addition & 1 deletion html/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ $(document).ready(function() {
if (response) {
const redirectCookie = this.getCookie('AUTH_REDIRECT');
if ((response.headers && response.headers['content-type'] == "text/html") ||
(response.status == 401) ||
(response.status == 401 && !response.request.responseURL.indexOf('/api/')) ||
(redirectCookie != null && redirectCookie.length > 0)) {
this.deleteCookie('AUTH_REDIRECT');
this.showLogin();
Expand Down
25 changes: 10 additions & 15 deletions server/gridmembershandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,12 @@ func (h *GridMembersHandler) postImport(w http.ResponseWriter, r *http.Request)
return
}

members, err := h.server.GridMembersstore.GetMembers(ctx)
if err != nil {
web.Respond(w, r, http.StatusInternalServerError, err)
return
}

_, gmExists := lo.Find(members, func(m *model.GridMember) bool {
return strings.EqualFold(m.Id, id)
})
if !gmExists {
web.Respond(w, r, http.StatusNotFound, errors.New("grid member not found"))
return
}

uploadLimit := int64(h.server.Config.ClientParams.GridParams.MaxUploadSize)
if uploadLimit == 0 {
uploadLimit = 25 * 1024 * 1024 // 25 MiB
}

err = r.ParseMultipartForm(uploadLimit)
err := r.ParseMultipartForm(uploadLimit)
if err != nil {
web.Respond(w, r, http.StatusBadRequest, err)
return
Expand Down Expand Up @@ -160,6 +146,15 @@ func (h *GridMembersHandler) postImport(w http.ResponseWriter, r *http.Request)

ext = ext[1:]

// auth check before we do anything async, before we even process the upload,
// if the user is authorized to complete this action
// TODO: When we re-evaluate the permissions needed to SendFile, we should
// add that same permission check here
if err := h.server.CheckAuthorized(ctx, "write", "events"); err != nil {
web.Respond(w, r, http.StatusUnauthorized, err)
return
}

baseTargetDir := h.server.Config.ImportUploadDir // "/opt/sensoroni/uploads/"
targetDir := filepath.Join(baseTargetDir, "processing", id)

Expand Down
68 changes: 68 additions & 0 deletions server/gridmembershandler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package server

import (
"bytes"
"context"
"encoding/hex"
"mime/multipart"
"net/http/httptest"
"testing"
"time"

"github.com/go-chi/chi"
"github.com/security-onion-solutions/securityonion-soc/config"
"github.com/security-onion-solutions/securityonion-soc/model"
"github.com/security-onion-solutions/securityonion-soc/web"
"github.com/stretchr/testify/assert"
)

type rejectAuthorizer struct{}

func (auth *rejectAuthorizer) CheckContextOperationAuthorized(ctx context.Context, operation string, target string) error {
return model.NewUnauthorized("", operation, target)
}
func (auth *rejectAuthorizer) CheckUserOperationAuthorized(user *model.User, operation string, target string) error {
return model.NewUnauthorized("", operation, target)
}

func TestImportAuth(t *testing.T) {
h := &GridMembersHandler{
server: &Server{
Authorizer: &rejectAuthorizer{},
Config: &config.ServerConfig{},
},
}

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)

ff, err := writer.CreateFormFile("attachment", "file.pcap")
if err != nil {
t.Fatal(err)
}

content, err := hex.DecodeString("a1b2c3d4000000")
assert.NoError(t, err)

_, err = ff.Write(content)
assert.NoError(t, err)

assert.NoError(t, writer.Close())

w := httptest.NewRecorder()

r := httptest.NewRequest("POST", "/1_standalone/import", bytes.NewReader(body.Bytes()))
r.Header.Add("Content-Type", "multipart/form-data; boundary="+writer.Boundary())

c := chi.NewRouteContext()
c.URLParams.Add("id", "1_standalone")
ctx := context.WithValue(context.Background(), chi.RouteCtxKey, c)
ctx = context.WithValue(ctx, web.ContextKeyRequestStart, time.Now())

r = r.WithContext(ctx)

h.postImport(w, r)

assert.Equal(t, 401, w.Code)
assert.Equal(t, web.GENERIC_ERROR_MESSAGE, w.Body.String())
}
10 changes: 8 additions & 2 deletions server/modules/salt/saltstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,11 @@ func (store *Saltstore) ManageMember(ctx context.Context, operation string, id s
}

func (store *Saltstore) SendFile(ctx context.Context, node string, from string, to string, cleanup bool) error {
// TODO: Auth Check
// TODO: re-evaluate necessary permissions when this feature is used for more
// than importing pcap/evtx.
if err := store.server.CheckAuthorized(ctx, "write", "events"); err != nil {
return err
}

args := map[string]string{
"command": "send-file",
Expand All @@ -1005,7 +1009,9 @@ func (store *Saltstore) SendFile(ctx context.Context, node string, from string,
}

func (store *Saltstore) Import(ctx context.Context, node string, file string, importer string) (*string, error) {
// TODO: Auth Check
if err := store.server.CheckAuthorized(ctx, "write", "events"); err != nil {
return nil, err
}

args := map[string]string{
"command": "import-file",
Expand Down

0 comments on commit e335d26

Please sign in to comment.