Files
paralus/pkg/service/audit_log_query.go
2022-04-08 17:42:26 +05:30

215 lines
5.1 KiB
Go

package service
import (
"bytes"
"encoding/json"
"fmt"
"strings"
v1 "github.com/RafayLabs/rcloud-base/proto/rpc/audit"
"google.golang.org/protobuf/types/known/structpb"
)
type AuditLogService struct {
auditQuery *ElasticSearchQuery
}
func NewAuditLogService(url string, auditPattern string, logPrefix string) (*AuditLogService, error) {
auditQuery, err := NewElasticSearchQuery(url, auditPattern, logPrefix)
if err != nil {
return nil, err
}
return &AuditLogService{auditQuery: auditQuery}, nil
}
func (a *AuditLogService) GetAuditLog(req *v1.AuditLogSearchRequest) (res *v1.AuditLogSearchResponse, err error) {
if err != nil {
return nil, err
}
projectID, err := getPrjectIdFromUrlScope(req.GetMetadata().UrlScope)
if err != nil {
return nil, err
}
req.Filter.ProjectIds = []string{projectID}
return a.GetAuditLogByProjects(req)
}
func validateQueryString(queryString string) error {
if strings.Contains(queryString, "*") {
return fmt.Errorf("Sorry. '*' is not supported in search query")
}
if len(queryString) > 0 && len(queryString) < 3 {
return fmt.Errorf("Search string has to be atleast 3 characters")
}
return nil
}
func getPrjectIdFromUrlScope(urlScope string) (string, error) {
s := strings.Split(urlScope, "/")
if len(s) != 2 {
_log.Errorw("Unable to retrieve projectID from urlScope", "urlScope", urlScope)
return "", fmt.Errorf("Unable to retrieve projectID from urlScope")
}
return s[1], nil
}
func (a *AuditLogService) GetAuditLogByProjects(req *v1.AuditLogSearchRequest) (res *v1.AuditLogSearchResponse, err error) {
// No embedding in golang/protoc (https://github.com/golang/protobuf/issues/192)
err = validateQueryString(req.GetFilter().QueryString)
if err != nil {
return nil, err
}
res = &v1.AuditLogSearchResponse{
Result: &structpb.Struct{},
}
var buf bytes.Buffer
var r map[string]interface{}
query := map[string]interface{}{
"_source": true,
"size": 500,
"query": map[string]interface{}{
"bool": map[string]interface{}{
"must": []map[string]interface{}{
// Add org and partner filter once we have to support multi-org
{
"term": map[string]interface{}{
"category": "AUDIT",
},
},
},
},
},
"sort": map[string]interface{}{
"timestamp": map[string]interface{}{
"order": "desc",
},
},
"aggs": map[string]interface{}{
"group_by_username": map[string]interface{}{
"terms": map[string]interface{}{
"field": "actor.account.username",
},
},
"group_by_type": map[string]interface{}{
"terms": map[string]interface{}{
"field": "type",
},
},
},
}
//aggregations
agg, _ := query["aggs"].(map[string]interface{})
if req.GetFilter().DashboardData {
agg["group_by_project"] = map[string]interface{}{
"terms": map[string]interface{}{
"field": "project_id",
"size": 1000,
},
"aggs": map[string]interface{}{
"group_by_username": map[string]interface{}{
"terms": map[string]interface{}{
"field": "actor.account.username",
"size": 1000,
},
},
"group_by_type": map[string]interface{}{
"terms": map[string]interface{}{
"field": "type",
"size": 1000,
},
},
},
}
}
// Filters
q, _ := query["query"].(map[string]interface{})
b, _ := q["bool"].(map[string]interface{})
m, _ := b["must"].([]map[string]interface{})
//Results not required in case of dashboard - only aggregations required
if req.GetFilter().DashboardData {
query["size"] = 0
}
// Add timefrom filter
if req.GetFilter().Timefrom != "" {
b["filter"] = map[string]interface{}{
"range": map[string]interface{}{
"timestamp": map[string]interface{}{
"gte": req.GetFilter().Timefrom,
"lt": "now",
},
},
}
}
// Add type
if req.GetFilter().Type != "" {
t := map[string]interface{}{
"term": map[string]interface{}{
"type": req.GetFilter().Type,
},
}
m = append(m, t)
}
// Add user
if req.GetFilter().User != "" {
t := map[string]interface{}{
"term": map[string]interface{}{
"actor.account.username": req.GetFilter().User,
},
}
m = append(m, t)
}
// Add user
if req.GetFilter().Client != "" {
t := map[string]interface{}{
"term": map[string]interface{}{
"client.type": req.GetFilter().Client,
},
}
m = append(m, t)
}
// ProjectIds
if len(req.GetFilter().ProjectIds) > 0 {
t := map[string]interface{}{
"terms": map[string]interface{}{
"project_id": req.GetFilter().ProjectIds,
},
}
m = append(m, t)
}
// query string
if req.GetFilter().QueryString != "" {
q := map[string]interface{}{
"query_string": map[string]interface{}{
"query": req.GetFilter().QueryString,
},
}
m = append(m, q)
}
b["must"] = m
if err := json.NewEncoder(&buf).Encode(query); err != nil {
_log.Errorw("Error encoding query:", " err", err)
return res, err
}
_log.Debug("Executing Query: ", q)
r, err = a.auditQuery.Handle(buf)
if err != nil {
return res, err
}
if r == nil {
return res, nil
}
// raw, err := json.Marshal(r)
// if err != nil {
// return res, err
// }
raw, err := structpb.NewStruct(r)
if err != nil {
return res, err
}
res = &v1.AuditLogSearchResponse{Result: raw}
return res, nil
}