Skip to content

Commit

Permalink
add support for passing enrichment data to middleware via context
Browse files Browse the repository at this point in the history
  • Loading branch information
fishnix authored and JAORMX committed Oct 5, 2022
1 parent ea348cf commit 8dc9017
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
14 changes: 14 additions & 0 deletions docs/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ When using the gin middleware, the audit ID will be added to the context and ava
auditID := c.GetString(mdw.AuditIDContextKey)
```

#### Addtional Data

Additional audit data can be passed down to the audit middleware via the context key
`AuditDataContextKey`. This can be leveraged to enrich the audit events with
diff information or other data for forensic analysis. The value is expected to be
a `*json.RawMessage` and you are responsible for ensuring proper JSON structure.

```golang
// add additional data to context to be logged in the
// audit event by the middleware
mydata := json.RawMessage(`{"foo":"bar"}`)
c.Set(mdw.AuditDataContextKey, &mydata)
```

### Audit event types

Audit event types identify the action that happened on a given request.
Expand Down
11 changes: 11 additions & 0 deletions ginaudit/mdw.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package ginaudit

import (
"encoding/json"
"fmt"
"io"
"sync"
Expand All @@ -28,6 +29,8 @@ import (
)

const (
// AuditDataContextKey is the gin context key for additional audit data.
AuditDataContextKey = "audit.data"
// AuditIDContextKey is the gin context key for the audit ID.
AuditIDContextKey = "audit.id"
)
Expand Down Expand Up @@ -125,6 +128,14 @@ func (m *Middleware) AuditWithType(t string) gin.HandlerFunc {
"path": path,
})

data, ok := c.Get(AuditDataContextKey)
if ok {
ed, ok := data.(*json.RawMessage)
if ok {
event.WithData(ed)
}
}

// persist event
m.write(event)
}
Expand Down
84 changes: 84 additions & 0 deletions ginaudit/mdw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const (
comp = "test"
)

var testData = json.RawMessage(`{"foo":"bar"}`)

type testCase struct {
name string
expectedEvent *auditevent.AuditEvent
Expand Down Expand Up @@ -141,6 +143,66 @@ func getTestCases() []testCase {
"X-User-Id": "user-ozz-from-header",
},
},
{
"user request succeeds, enriched by context data",
auditevent.NewAuditEvent(
"GET:/changes",
auditevent.EventSource{
Type: "IP",
Value: "127.0.0.1",
},
auditevent.OutcomeSucceeded,
map[string]string{
"user": "user-ozz",
"sub": "sub-ozz",
},
comp,
).WithTarget(map[string]string{
"path": "/changes",
}).WithData(&testData),
http.MethodGet,
nil,
},
{
"user request denied, encriched by context data",
auditevent.NewAuditEvent(
"GET:/changes/denied",
auditevent.EventSource{
Type: "IP",
Value: "127.0.0.1",
},
auditevent.OutcomeDenied,
map[string]string{
"user": "Unknown",
"sub": "Unknown",
},
comp,
).WithTarget(map[string]string{
"path": "/changes/denied",
}).WithData(&testData),
http.MethodGet,
nil,
},
{
"user request succeeds, context data added as wrong type",
auditevent.NewAuditEvent(
"GET:/nodata",
auditevent.EventSource{
Type: "IP",
Value: "127.0.0.1",
},
auditevent.OutcomeSucceeded,
map[string]string{
"user": "user-ozz",
"sub": "sub-ozz",
},
comp,
).WithTarget(map[string]string{
"path": "/nodata",
}),
http.MethodGet,
nil,
},
}
}

Expand Down Expand Up @@ -185,6 +247,28 @@ func setFixtures(t *testing.T, w io.Writer, pr prometheus.Registerer) (*gin.Engi
c.JSON(http.StatusForbidden, "denied")
})

// allowed with user, enriched by context data
r.GET("/changes", func(c *gin.Context) {
c.Set("jwt.user", "user-ozz")
c.Set("jwt.subject", "sub-ozz")
c.Set(ginaudit.AuditDataContextKey, &testData)
c.JSON(http.StatusOK, "ok")
})

// denied with no user, enriched by context data
r.GET("/changes/denied", func(c *gin.Context) {
c.Set(ginaudit.AuditDataContextKey, &testData)
c.JSON(http.StatusForbidden, "denied")
})

// context data of wrong type
r.GET("/nodata", func(c *gin.Context) {
c.Set("jwt.user", "user-ozz")
c.Set("jwt.subject", "sub-ozz")
c.Set(ginaudit.AuditDataContextKey, "some random string")
c.JSON(http.StatusOK, "ok")
})

return r, mdw
}

Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down

0 comments on commit 8dc9017

Please sign in to comment.