Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Back office events #24

Merged
merged 16 commits into from
Apr 16, 2019
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cmd/keycloakb/keycloak_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,19 @@ func main() {
{
var managementLogger = log.With(logger, "svc", "management")

// module to store API calls of the back office to the DB
var eventsDBModule event.EventsDBModule
{
eventsDBModule = event.NewEventsDBModule(eventsDBConn)
eventsDBModule = event.MakeEventsDBModuleInstrumentingMW(influxMetrics.NewHistogram("eventsDB_module"))(eventsDBModule)
eventsDBModule = event.MakeEventsDBModuleLoggingMW(log.With(managementLogger, "mw", "module", "unit", "eventsDB"))(eventsDBModule)
eventsDBModule = event.MakeEventsDBModuleTracingMW(tracer)(eventsDBModule)

}

var keycloakComponent management.Component
{
keycloakComponent = management.NewComponent(keycloakClient)
keycloakComponent = management.NewComponent(keycloakClient, eventsDBModule)
}

var getRealmEndpoint endpoint.Endpoint
Expand Down
114 changes: 67 additions & 47 deletions pkg/event/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"encoding/json"
"fmt"
"regexp"
"strings"
"sync"
"time"
Expand Down Expand Up @@ -122,48 +123,44 @@ func (c *adminComponent) AdminEvent(ctx context.Context, adminEvent *fb.AdminEve
func addCTtypeToEvent(event map[string]string) map[string]string {
// add the ct_event_type

switch opType := event["operationType"]; opType {
addInfo := []byte(event["additional_info"])
var f map[string]string
_ = json.Unmarshal(addInfo, &f)

switch opType := event["kc_operation_type"]; opType {
case "CREATE":
//ACCOUNT_CREATED
// check if the resourcePath starts with prefix users
if strings.HasPrefix(event["resourcePath"], "users") {
if strings.HasPrefix(f["resource_path"], "users") {
event["ct_event_type"] = "ACCOUNT_CREATED"
return event
}
case "ACTION":
//ACTIVATION_EMAIL_SENT
// check if the resourcePath ends with sufix send-verify-email
fperot74 marked this conversation as resolved.
Show resolved Hide resolved
if strings.HasSuffix(event["resourcePath"], "send-verify-email") {
if strings.HasSuffix(f["resource_path"], "send-verify-email") {
event["ct_event_type"] = "ACTIVATION_EMAIL_SENT"
return event
}
default:

}

switch t := event["type"]; t {
switch t := event["kc_event_type"]; t {
case "CUSTOM_REQUIRED_ACTION":
//EMAIL_CONFIRMED
eventDetails := []byte(event["details"])
var f map[string]string
_ = json.Unmarshal(eventDetails, &f)

if f["custom_required_action"] == "VERIFY_EMAIL" {
event["ct_event_type"] = "EMAIL_CONFIRMED"
return event
}
case "EXECUTE_ACTION_TOKEN_ERROR":
//CONFIRM_EMAIL_EXPIRED
if event["error"] == "expired_code" {
if f["error"] == "expired_code" {
event["ct_event_type"] = "CONFIRM_EMAIL_EXPIRED"
return event
}
case "UPDATE_PASSWORD":
//PASSWORD_RESET
eventDetails := []byte(event["details"])
var f map[string]string
_ = json.Unmarshal(eventDetails, &f)

if f["custom_required_action"] == "sms-password-set" {
event["ct_event_type"] = "PASSWORD_RESET"
return event
Expand Down Expand Up @@ -195,33 +192,40 @@ func addCTtypeToEvent(event map[string]string) map[string]string {

func adminEventToMap(adminEvent *fb.AdminEvent) map[string]string {
var adminEventMap = make(map[string]string)
adminEventMap["uid"] = fmt.Sprint(adminEvent.Uid())
var addInfo = make(map[string]string)

addInfo["uid"] = fmt.Sprint(adminEvent.Uid())

time := epochMilliToTime(adminEvent.Time())
adminEventMap["time"] = time.Format("2006-01-02T15:04:05.000Z")
time := epochMilliToTime(adminEvent.Time()).UTC()
adminEventMap["audit_time"] = time.Format("2006-01-02 15:04:05.000") //audit_time

adminEventMap["realmId"] = string(adminEvent.RealmId())
adminEventMap["realm_name"] = string(adminEvent.RealmId()) //realm_name
adminEventMap["origin"] = "keycloak" //origin

authDetails := adminEvent.AuthDetails(nil)
var authDetailsMap map[string]string
authDetailsMap = make(map[string]string)
authDetailsMap["clientId"] = string(authDetails.ClientId())
authDetailsMap["ipAddress"] = string(authDetails.IpAddress())
authDetailsMap["realmId"] = string(authDetails.RealmId())
authDetailsMap["userId"] = string(authDetails.UserId())

// BE AWARE: error is not treated
authDetailsJson, _ := json.Marshal(authDetailsMap)
adminEventMap["authDetails"] = string(authDetailsJson)

adminEventMap["resourceType"] = string(adminEvent.ResourceType())
adminEventMap["operationType"] = fb.EnumNamesOperationType[int8(adminEvent.OperationType())]
adminEventMap["resourcePath"] = string(adminEvent.ResourcePath())
adminEventMap["representation"] = string(adminEvent.Representation())
adminEventMap["error"] = string(adminEvent.Error())
adminEventMap["client_id"] = string(authDetails.ClientId()) //client_id
addInfo["ip_address"] = string(authDetails.IpAddress())
adminEventMap["agent_realm_name"] = string(authDetails.RealmId()) // agent_realm_name
adminEventMap["agent_user_id"] = string(authDetails.UserId()) //agent_user_id

addInfo["resource_type"] = string(adminEvent.ResourceType())
adminEventMap["kc_operation_type"] = fb.EnumNamesOperationType[int8(adminEvent.OperationType())] //kc_operation_type
addInfo["resource_path"] = string(adminEvent.ResourcePath())
reg := regexp.MustCompile(`[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}`)
if strings.HasPrefix(addInfo["resourcePath"], "users") {
adminEventMap["user_id"] = string(reg.Find([]byte(addInfo["resourcePath"]))) //user_id
}

addInfo["representation"] = string(adminEvent.Representation())
addInfo["error"] = string(adminEvent.Error())
//all the admin events have, by default, the ct_event_type set to admin
adminEventMap["ct_event_type"] = "ADMIN"

// BE AWARE: error is not treated
infoJson, _ := json.Marshal(addInfo)
adminEventMap["additional_info"] = string(infoJson)

//set the correct ct_event_type for actions like create_account, etc.
adminEventMap = addCTtypeToEvent(adminEventMap)

Expand All @@ -230,36 +234,52 @@ func adminEventToMap(adminEvent *fb.AdminEvent) map[string]string {

func eventToMap(event *fb.Event) map[string]string {
var eventMap = make(map[string]string)
eventMap["uid"] = fmt.Sprint(event.Uid())
var addInfo = make(map[string]string)
// if an event has the ct_event_type set already, the flag avoids rewriting it
var doNotSetCTEventType bool = false

addInfo["uid"] = fmt.Sprint(event.Uid())

time := epochMilliToTime(event.Time()).UTC()
eventMap["audit_time"] = time.Format("2006-01-02 15:04:05.000") //audit_time
fperot74 marked this conversation as resolved.
Show resolved Hide resolved

time := epochMilliToTime(event.Time())
eventMap["time"] = time.Format("2006-01-02T15:04:05.000Z")
eventMap["kc_event_type"] = fb.EnumNamesEventType[int8(event.Type())] // kc_event_type
eventMap["realm_name"] = string(event.RealmId()) //realm_name
eventMap["client_id"] = string(event.ClientId()) //client_id
eventMap["agent_user_id"] = string(event.UserId()) //agent_user_id
eventMap["user_id"] = string(event.UserId()) //user_id
//Note: we make the assumption that the agent and the user are the same in the case of the events that are not admin events

eventMap["type"] = fb.EnumNamesEventType[int8(event.Type())]
eventMap["realmId"] = string(event.RealmId())
eventMap["clientId"] = string(event.ClientId())
eventMap["userId"] = string(event.UserId())
eventMap["sessionId"] = string(event.SessionId())
eventMap["ipAddress"] = string(event.IpAddress())
eventMap["error"] = string(event.Error())
addInfo["session_id"] = string(event.SessionId())
addInfo["ip_address"] = string(event.IpAddress())
addInfo["error"] = string(event.Error())
eventMap["origin"] = "keycloak" //origin

var detailsMap = make(map[string]string)
var detailsLength = event.DetailsLength()
for i := 0; i < detailsLength; i++ {
var tuple = new(fb.Tuple)
event.Details(tuple, i)
if string(tuple.Key()) == "ct_event_type" {
eventMap[string(tuple.Key())] = string(tuple.Value())
doNotSetCTEventType = true
} else {
detailsMap[string(tuple.Key())] = string(tuple.Value())
if string(tuple.Key()) == "username" {
eventMap["agent_username"] = string(tuple.Value()) //agent_username
eventMap[string(tuple.Key())] = string(tuple.Value()) //username
} else {
addInfo[string(tuple.Key())] = string(tuple.Value())
}

}
}

// BE AWARE: error is not treated
detailsJson, _ := json.Marshal(detailsMap)
eventMap["details"] = string(detailsJson)
infoJson, _ := json.Marshal(addInfo)
eventMap["additional_info"] = string(infoJson)

eventMap = addCTtypeToEvent(eventMap)
if !doNotSetCTEventType {
eventMap = addCTtypeToEvent(eventMap)
}

return eventMap
}
Expand Down
78 changes: 60 additions & 18 deletions pkg/event/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package event

import (
"context"
"encoding/json"
"errors"
"strconv"
"testing"
Expand Down Expand Up @@ -123,13 +124,14 @@ func TestAdminComponent(t *testing.T) {
func TestEventToMap(t *testing.T) {
var uid int64 = 1234
var epoch = int64(1547127600485)
var etype int8
var etype int8 = 6
var realmID = "realm"
var clientID = "client"
var userID = "user"
var sessionID = "session"
var ipAddr = "ipAddress"
var error = "error"
var username = "test_username"

var event *fb.Event
{
Expand All @@ -143,7 +145,7 @@ func TestEventToMap(t *testing.T) {
var error = builder.CreateString(error)

var key1 = builder.CreateString("username")
var value1 = builder.CreateString("test_username")
var value1 = builder.CreateString(username)
fb.TupleStart(builder)
fb.TupleAddKey(builder, key1)
fb.TupleAddValue(builder, value1)
Expand Down Expand Up @@ -178,15 +180,51 @@ func TestEventToMap(t *testing.T) {
}

var m = eventToMap(event)
assert.Equal(t, strconv.FormatInt(uid, 10), m["uid"])
assert.Equal(t, time.Unix(0, epoch*1000000).Format("2006-01-02T15:04:05.000Z"), m["time"])
assert.Equal(t, fb.EnumNamesEventType[int8(etype)], m["type"])
assert.Equal(t, realmID, m["realmId"])
assert.Equal(t, clientID, m["clientId"])
assert.Equal(t, userID, m["userId"])
assert.Equal(t, sessionID, m["sessionId"])
assert.Equal(t, ipAddr, m["ipAddress"])
assert.Equal(t, error, m["error"])
assert.Equal(t, time.Unix(0, epoch*1000000).UTC().Format("2006-01-02 15:04:05.000"), m["audit_time"])
assert.Equal(t, fb.EnumNamesEventType[int8(etype)], m["kc_event_type"])
assert.Equal(t, realmID, m["realm_name"])
assert.Equal(t, clientID, m["client_id"])
assert.Equal(t, userID, m["user_id"])
assert.Equal(t, username, m["username"])
var f = make(map[string]string)
err := json.Unmarshal([]byte(m["additional_info"]), &f)
assert.Nil(t, err)
assert.Equal(t, strconv.FormatInt(uid, 10), f["uid"])
assert.Equal(t, sessionID, f["session_id"])
assert.Equal(t, ipAddr, f["ip_address"])
assert.Equal(t, error, f["error"])
assert.Equal(t, "", m["ct_event_type"])

}

func TestEventToMapNewCTEvent(t *testing.T) {
var customEvent = "CUSTOM_EVENT"
var etype int8 = 6

var event *fb.Event
{
var builder = flatbuffers.NewBuilder(0)
var key1 = builder.CreateString("ct_event_type")
var value1 = builder.CreateString(customEvent)
fb.TupleStart(builder)
fb.TupleAddKey(builder, key1)
fb.TupleAddValue(builder, value1)
var detail1 = fb.TupleEnd(builder)

fb.EventStartDetailsVector(builder, 1)
builder.PrependUOffsetT(detail1)
var details = builder.EndVector(1)

fb.EventStart(builder)
fb.EventAddDetails(builder, details)
fb.EventAddType(builder, etype)
var eventOffset = fb.EventEnd(builder)
builder.Finish(eventOffset)
event = fb.GetRootAsEvent(builder.FinishedBytes(), 0)
}

var m = eventToMap(event)
assert.Equal(t, customEvent, m["ct_event_type"])

}

Expand Down Expand Up @@ -422,13 +460,17 @@ func TestAdminEventToMap(t *testing.T) {
}

var m = adminEventToMap(adminEvent)
assert.Equal(t, strconv.FormatInt(uid, 10), m["uid"])
assert.Equal(t, time.Unix(0, epoch*1000000).Format("2006-01-02T15:04:05.000Z"), m["time"])
assert.Equal(t, fb.EnumNamesOperationType[int8(optype)], m["operationType"])
assert.Equal(t, realmID, m["realmId"])
assert.Equal(t, resourcePath, m["resourcePath"])
assert.Equal(t, representation, m["representation"])
assert.Equal(t, error, m["error"])

assert.Equal(t, time.Unix(0, epoch*1000000).UTC().Format("2006-01-02 15:04:05.000"), m["audit_time"])
assert.Equal(t, fb.EnumNamesOperationType[int8(optype)], m["kc_operation_type"])
assert.Equal(t, realmID, m["realm_name"])
var f = make(map[string]string)
err := json.Unmarshal([]byte(m["additional_info"]), &f)
assert.Nil(t, err)
assert.Equal(t, strconv.FormatInt(uid, 10), f["uid"])
assert.Equal(t, resourcePath, f["resource_path"])
assert.Equal(t, representation, f["representation"])
assert.Equal(t, error, f["error"])
assert.Equal(t, "ADMIN", m["ct_event_type"])

}
Expand Down
Loading