diff --git a/go/cron/flush_radius_audit_log_job.go b/go/cron/flush_radius_audit_log_job.go index df15d1355b7..5efcec248f1 100644 --- a/go/cron/flush_radius_audit_log_job.go +++ b/go/cron/flush_radius_audit_log_job.go @@ -122,24 +122,25 @@ func (j *FlushRadiusAuditLogJob) flushLogs(entries [][]interface{}) error { } // REPLACE in node_tls - sqlTLS, argsTLS, err := j.buildQueryTLS(entries) - if err != nil { - return err - } + sqlTLS, argsTLS, run := j.buildQueryTLS(entries) + if run { + res, err = db.ExecContext( + ctx, + sqlTLS, + argsTLS..., + ) - res, err = db.ExecContext( - ctx, - sqlTLS, - argsTLS..., - ) + if err != nil { + return fmt.Errorf("Error with %s\n%v: %w", sqlTLS, argsTLS, err) + } - if err != nil { - return err - } + _, err = res.RowsAffected() + if err != nil { + return err + } - _, err = res.RowsAffected() - if err != nil { - return err + } else { + fmt.Printf("Zero Args\n") } log.LogInfo(ctx, fmt.Sprintf("Flushed %d radius_audit_log", rows)) @@ -254,7 +255,12 @@ func (j *FlushRadiusAuditLogJob) argsFromEntry(entry []interface{}) []interface{ return args } -func (j *FlushRadiusAuditLogJob) buildQueryTLS(entries [][]interface{}) (string, []interface{}, error) { +func (j *FlushRadiusAuditLogJob) buildQueryTLS(entries [][]interface{}) (string, []interface{}, bool) { + args := j.argsFromEntriesForTLS(entries) + if len(args) == 0 { + return "", nil, false + } + sql := ` INSERT INTO node_tls ( @@ -271,7 +277,7 @@ INSERT INTO node_tls ) VALUES ` bind := "( ?" + strings.Repeat(",?", NODE_TLS_COLUMN_COUNT-1) + ")" - sql += bind + strings.Repeat(","+bind, len(entries)-1) + sql += bind + strings.Repeat(","+bind, (len(args)/NODE_TLS_COLUMN_COUNT)-1) sql += ` ON DUPLICATE KEY UPDATE TLSCertSerial = VALUES(TLSCertSerial), TLSCertExpiration = VALUES(TLSCertExpiration), TLSCertValidSince = VALUES(TLSCertValidSince), @@ -286,13 +292,7 @@ VALUES ` TLSClientCertX509v3ExtendedKeyUsageOID = VALUES(TLSClientCertX509v3ExtendedKeyUsageOID) ` - args := make([]interface{}, 0, NODE_TLS_COLUMN_COUNT) - for _, e := range entries { - if keyExists(e[1].(map[string]interface{}), "Calling-Station-Id") && keyExists(e[1].(map[string]interface{}), "TLS-Client-Cert-Common-Name") { - args = append(args, j.argsFromEntryForTLS(e)...) - } - } - return sql, args, nil + return sql, args, true } func keyExists(myMap map[string]interface{}, key string) bool { @@ -300,11 +300,36 @@ func keyExists(myMap map[string]interface{}, key string) bool { return exists } -func (j *FlushRadiusAuditLogJob) argsFromEntryForTLS(entry []interface{}) []interface{} { +func (j *FlushRadiusAuditLogJob) argsFromEntriesForTLS(entries [][]interface{}) []interface{} { + args := make([]interface{}, 0, len(entries)*NODE_TLS_COLUMN_COUNT) + for _, e := range entries { + if len(e) < 1 { + continue + } + lookup, ok := e[1].(map[string]interface{}) + if !ok { + continue + } + if !keyExists(lookup, "Calling-Station-Id") { + fmt.Printf("Not found Calling-Station-Id\n") + continue + } + + if !keyExists(lookup, "TLS-Client-Cert-Common-Name") { + fmt.Printf("Not found TLS-Client-Cert-Common-Name\n") + continue + } + + args = append(args, j.argsFromEntryForTLS(lookup)...) + + } + + return args +} + +func (j *FlushRadiusAuditLogJob) argsFromEntryForTLS(lookup map[string]interface{}) []interface{} { args := make([]interface{}, NODE_TLS_COLUMN_COUNT) - var request map[string]interface{} - request = entry[1].(map[string]interface{}) - request = parseRequestArgs(request) + request := parseRequestArgs(lookup) args[0] = formatRequestValue(request["Calling-Station-Id"], "") args[1] = formatRequestValue(request["TLS-Cert-Serial"], "N/A") args[2] = formatRequestValue(request["TLS-Cert-Expiration"], "N/A") diff --git a/go/cron/flush_radius_audit_log_job_test.go b/go/cron/flush_radius_audit_log_job_test.go index 6357be092a9..d68b2461489 100644 --- a/go/cron/flush_radius_audit_log_job_test.go +++ b/go/cron/flush_radius_audit_log_job_test.go @@ -11,6 +11,279 @@ const RADIUS_SAMPLE = `[["Accept",{"User-Name":{"type":"string","value":"a0:00:0 const RADIUS_ENTRY = `["Accept",{"User-Name":{"type":"string","value":"a0:00:00:00:00:01"},"User-Password":{"type":"string","value":"******"},"NAS-IP-Address":{"type":"ipaddr","value":"192.168.8.1"},"NAS-Port":{"type":"integer","value":1},"Service-Type":{"type":"integer","value":"Call-Check"},"Called-Station-Id":{"type":"string","value":"03:00:00:00:00:01"},"Calling-Station-Id":{"type":"string","value":"a1:00:00:00:00:01"},"NAS-Port-Type":{"type":"integer","value":"Wireless-802.11"},"Event-Timestamp":{"type":"date","value":"May 24 2023 14:50:28 UTC"},"Stripped-User-Name":{"type":"string","value":"a0:00:00:00:00:01"},"Realm":{"type":"string","value":"null"},"FreeRADIUS-Client-IP-Address":{"type":"ipaddr","value":"172.105.101.170"},"PacketFence-KeyBalanced":{"type":"string","value":"16d01a2b08829d827b5be1abae145f0a"},"PacketFence-Radius-Ip":{"type":"string","value":"172.105.101.170"}},{"REST-HTTP-Status-Code":{"type":"integer","value":200},"Tunnel-Private-Group-Id":{"type":"string","value":"2"},"Tunnel-Medium-Type":{"type":"integer","value":"IEEE-802"},"Tunnel-Type":{"type":"integer","value":"VLAN"}},{"PacketFence-Switch-Id":{"type":"string","value":"192.168.8.1"},"PacketFence-Switch-Mac":{"type":"string","value":"03:00:00:00:00:01"},"PacketFence-Switch-Ip-Address":{"type":"string","value":"192.168.8.1"},"PacketFence-IfIndex":{"type":"string","value":"1"},"PacketFence-Connection-Type":{"type":"string","value":"Wireless-802.11-NoEAP"},"Auth-Type":{"type":"integer","value":"Accept"},"PacketFence-Role":{"type":"string","value":"registration"},"PacketFence-Status":{"type":"string","value":"unreg"},"PacketFence-Profile":{"type":"string","value":"default"},"PacketFence-AutoReg":{"type":"string","value":"0"},"PacketFence-IsPhone":{"type":"string","value":""},"PacketFence-Request-Time":{"type":"integer","value":0}}]` +const RADIUS_SAMPLE_TLS = ` +[ + [ + "Accept", + { + "User-Name": { + "type": "string", + "value": "a0:00:00:00:00:01" + }, + "User-Password": { + "type": "string", + "value": "******" + }, + "NAS-IP-Address": { + "type": "ipaddr", + "value": "192.168.8.1" + }, + "NAS-Port": { + "type": "integer", + "value": 1 + }, + "Service-Type": { + "type": "integer", + "value": "Call-Check" + }, + "Called-Station-Id": { + "type": "string", + "value": "03:00:00:00:00:01" + }, + "Calling-Station-Id": { + "type": "string", + "value": "a1:00:00:00:00:01" + }, + "NAS-Port-Type": { + "type": "integer", + "value": "Wireless-802.11" + }, + "Event-Timestamp": { + "type": "date", + "value": "May 24 2023 14:50:28 UTC" + }, + "Stripped-User-Name": { + "type": "string", + "value": "a0:00:00:00:00:01" + }, + "Realm": { + "type": "string", + "value": "null" + }, + "FreeRADIUS-Client-IP-Address": { + "type": "ipaddr", + "value": "172.105.101.170" + }, + "PacketFence-KeyBalanced": { + "type": "string", + "value": "16d01a2b08829d827b5be1abae145f0a" + }, + "PacketFence-Radius-Ip": { + "type": "string", + "value": "172.105.101.170" + }, + "TLS-Client-Cert-Common-Name": { + "type": "string", + "value": "bob" + } + }, + { + "REST-HTTP-Status-Code": { + "type": "integer", + "value": 200 + }, + "Tunnel-Private-Group-Id": { + "type": "string", + "value": "2" + }, + "Tunnel-Medium-Type": { + "type": "integer", + "value": "IEEE-802" + }, + "Tunnel-Type": { + "type": "integer", + "value": "VLAN" + } + }, + { + "PacketFence-Switch-Id": { + "type": "string", + "value": "192.168.8.1" + }, + "PacketFence-Switch-Mac": { + "type": "string", + "value": "03:00:00:00:00:01" + }, + "PacketFence-Switch-Ip-Address": { + "type": "string", + "value": "192.168.8.1" + }, + "PacketFence-IfIndex": { + "type": "string", + "value": "1" + }, + "PacketFence-Connection-Type": { + "type": "string", + "value": "Wireless-802.11-NoEAP" + }, + "Auth-Type": { + "type": "integer", + "value": "Accept" + }, + "PacketFence-Role": { + "type": "string", + "value": "registration" + }, + "PacketFence-Status": { + "type": "string", + "value": "unreg" + }, + "PacketFence-Profile": { + "type": "string", + "value": "default" + }, + "PacketFence-AutoReg": { + "type": "string", + "value": "0" + }, + "PacketFence-IsPhone": { + "type": "string", + "value": "" + }, + "PacketFence-Request-Time": { + "type": "integer", + "value": 0 + } + } + ] +] +` + +const RADIUS_ENTRY_TLS = ` +[ + "Accept", + { + "User-Name": { + "type": "string", + "value": "a0:00:00:00:00:01" + }, + "User-Password": { + "type": "string", + "value": "******" + }, + "NAS-IP-Address": { + "type": "ipaddr", + "value": "192.168.8.1" + }, + "NAS-Port": { + "type": "integer", + "value": 1 + }, + "Service-Type": { + "type": "integer", + "value": "Call-Check" + }, + "Called-Station-Id": { + "type": "string", + "value": "03:00:00:00:00:01" + }, + "Calling-Station-Id": { + "type": "string", + "value": "a1:00:00:00:00:01" + }, + "NAS-Port-Type": { + "type": "integer", + "value": "Wireless-802.11" + }, + "Event-Timestamp": { + "type": "date", + "value": "May 24 2023 14:50:28 UTC" + }, + "Stripped-User-Name": { + "type": "string", + "value": "a0:00:00:00:00:01" + }, + "Realm": { + "type": "string", + "value": "null" + }, + "FreeRADIUS-Client-IP-Address": { + "type": "ipaddr", + "value": "172.105.101.170" + }, + "PacketFence-KeyBalanced": { + "type": "string", + "value": "16d01a2b08829d827b5be1abae145f0a" + }, + "PacketFence-Radius-Ip": { + "type": "string", + "value": "172.105.101.170" + }, + "TLS-Client-Cert-Common-Name": { + "type": "string", + "value": "bob" + } + }, + { + "REST-HTTP-Status-Code": { + "type": "integer", + "value": 200 + }, + "Tunnel-Private-Group-Id": { + "type": "string", + "value": "2" + }, + "Tunnel-Medium-Type": { + "type": "integer", + "value": "IEEE-802" + }, + "Tunnel-Type": { + "type": "integer", + "value": "VLAN" + } + }, + { + "PacketFence-Switch-Id": { + "type": "string", + "value": "192.168.8.1" + }, + "PacketFence-Switch-Mac": { + "type": "string", + "value": "03:00:00:00:00:01" + }, + "PacketFence-Switch-Ip-Address": { + "type": "string", + "value": "192.168.8.1" + }, + "PacketFence-IfIndex": { + "type": "string", + "value": "1" + }, + "PacketFence-Connection-Type": { + "type": "string", + "value": "Wireless-802.11-NoEAP" + }, + "Auth-Type": { + "type": "integer", + "value": "Accept" + }, + "PacketFence-Role": { + "type": "string", + "value": "registration" + }, + "PacketFence-Status": { + "type": "string", + "value": "unreg" + }, + "PacketFence-Profile": { + "type": "string", + "value": "default" + }, + "PacketFence-AutoReg": { + "type": "string", + "value": "0" + }, + "PacketFence-IsPhone": { + "type": "string", + "value": "" + }, + "PacketFence-Request-Time": { + "type": "integer", + "value": 0 + } + } +] +` const RADIUS_ENTRY_BAD = `["Accept",{"User-Name ":{"type":"string","value":"a0:00:00:00:00:01"},"User-Password":{"type":"string","value":"******"},"NAS-IP-Address":{"type":"ipaddr","value":"192.168.8.1"},"NAS-Port":{"type":"integer","value":1},"Service-Type":{"type":"integer","value":"Call-Check"},"Called-Station-Id":{"type":"string","value":"03:00:00:00:00:01"},"Calling-Station-Id":{"type":"string","value":"a1:00:00:00:00:01"},"NAS-Port-Type":{"type":"integer","value":"Wireless-802.11"},"Event-Timestamp":{"type":"date","value":"May 24 2023 14:50:28 UTC"},"Stripped-User-Name":{"type":"string","value":"a0:00:00:00:00:01"},"Realm":{"type":"string","value":"null"},"FreeRADIUS-Client-IP-Address":{"type":"ipaddr","value":"172.105.101.170"},"PacketFence-KeyBalanced":{"type":"string","value":"16d01a2b08829d827b5be1abae145f0a"},"PacketFence-Radius-Ip":{"type":"string","value":"172.105.101.170"}},{"REST-HTTP-Status-Code":{"type":"integer","value":200},"Tunnel-Private-Group-Id":{"type":"string","value":"2"},"Tunnel-Medium-Type":{"type":"integer","value":"IEEE-802"},"Tunnel-Type":{"type":"integer","value":"VLAN"}},{"PacketFence-Switch-Id":{"type":"string","value":"192.168.8.1"},"PacketFence-Switch-Mac":{"type":"string","value":"03:00:00:00:00:01"},"PacketFence-Switch-Ip-Address":{"type":"string","value":"192.168.8.1"},"PacketFence-IfIndex":{"type":"string","value":"1"},"PacketFence-Connection-Type":{"type":"string","value":"Wireless-802.11-NoEAP"},"Auth-Type":{"type":"integer","value":"Accept"},"PacketFence-Role":{"type":"string","value":"registration"},"PacketFence-Status":{"type":"string","value":"unreg"},"PacketFence-Profile":{"type":"string","value":"default"},"PacketFence-AutoReg":{"type":"string","value":"0"},"PacketFence-IsPhone":{"type":"string","value":""},"PacketFence-Request-Time":{"type":"integer","value":0}}]` @@ -108,6 +381,74 @@ func TestFlushRadiusAuditLogFromRedis(t *testing.T) { } } +func TestFlushRadiusAuditLogWithTLSFromRedis(t *testing.T) { + var entries [][]interface{} = make([][]interface{}, 1) + json.Unmarshal([]byte(RADIUS_SAMPLE_TLS), &entries) + job := NewFlushRadiusAuditLogJob(map[string]interface{}{ + "batch": 100.0, + "type": "flush_radius_audit_log_job", + "status": "enabled", + "description": "Test", + "schedule": "@every 1m", + "timeout": 1.0, + "local": "enabled", + }) + ctx := context.Background() + + j := job.(*FlushRadiusAuditLogJob) + db, err := getDb() + if err != nil { + t.Fatalf("No database %s", err.Error()) + } + redis := getRedisClient() + redis.Del(ctx, "RADIUS_AUDIT_LOG") + redis.LPush(ctx, "RADIUS_AUDIT_LOG", RADIUS_ENTRY_TLS, base64.StdEncoding.EncodeToString([]byte(RADIUS_ENTRY_TLS))) + + res, err := db.Exec("DELETE FROM radius_audit_log;") + if err != nil { + t.Fatalf("Delete from %s", err.Error()) + } + _ = res + + res, err = db.Exec("DELETE FROM node_tls;") + if err != nil { + t.Fatalf("Delete from %s", err.Error()) + } + _ = res + + j.Run() + + row := db.QueryRow("SELECT COUNT(id) FROM radius_audit_log;") + if err := row.Err(); err != nil { + t.Fatalf("Delete from %s", err.Error()) + } + + count := 0 + err = row.Scan(&count) + if err != nil { + t.Fatalf("Cannot flush logs %s", err.Error()) + } + + if count != 1 { + t.Fatalf("Flush count logs expect %d, got %d", 1, count) + } + + row = db.QueryRow("SELECT COUNT(*) FROM node_tls;") + if err := row.Err(); err != nil { + t.Fatalf("Delete from %s", err.Error()) + } + + count = 0 + err = row.Scan(&count) + if err != nil { + t.Fatalf("Cannot flush logs %s", err.Error()) + } + + if count != 1 { + t.Fatalf("Flush count logs expect %d, got %d", 1, count) + } +} + func errorCheck(t *testing.T, name string, err error) { if err != nil { t.Fatalf("Cannot flush logs %s", err.Error())