forked from baron/baron-sso
RP 로그인 이력 통합
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ClickHouse/clickhouse-go/v2"
|
||||
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
|
||||
@@ -36,10 +37,77 @@ func (r *OathkeeperClickHouseRepository) FindPageBySubject(ctx context.Context,
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
query := `
|
||||
SELECT timestamp, request_id, method, path, status, latency_ms, rp, action, target, subject, client_ip, user_agent, decision, trace_id, span_id, raw
|
||||
FROM oathkeeper_access_logs
|
||||
`
|
||||
query, args := buildOathkeeperQuery(subject, limit, cursor, true)
|
||||
rows, err := r.conn.Query(ctx, query, args...)
|
||||
if err != nil && isMissingColumnError(err, "client_id") {
|
||||
query, args = buildOathkeeperQuery(subject, limit, cursor, false)
|
||||
rows, err = r.conn.Query(ctx, query, args...)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query oathkeeper logs: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
withClientID := strings.Contains(query, "client_id")
|
||||
var logs []domain.OathkeeperAccessLog
|
||||
for rows.Next() {
|
||||
var log domain.OathkeeperAccessLog
|
||||
if withClientID {
|
||||
if err := rows.Scan(
|
||||
&log.Timestamp,
|
||||
&log.RequestID,
|
||||
&log.Method,
|
||||
&log.Path,
|
||||
&log.Status,
|
||||
&log.LatencyMs,
|
||||
&log.ClientID,
|
||||
&log.RP,
|
||||
&log.Action,
|
||||
&log.Target,
|
||||
&log.Subject,
|
||||
&log.ClientIP,
|
||||
&log.UserAgent,
|
||||
&log.Decision,
|
||||
&log.TraceID,
|
||||
&log.SpanID,
|
||||
&log.Raw,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan oathkeeper log: %w", err)
|
||||
}
|
||||
} else {
|
||||
if err := rows.Scan(
|
||||
&log.Timestamp,
|
||||
&log.RequestID,
|
||||
&log.Method,
|
||||
&log.Path,
|
||||
&log.Status,
|
||||
&log.LatencyMs,
|
||||
&log.RP,
|
||||
&log.Action,
|
||||
&log.Target,
|
||||
&log.Subject,
|
||||
&log.ClientIP,
|
||||
&log.UserAgent,
|
||||
&log.Decision,
|
||||
&log.TraceID,
|
||||
&log.SpanID,
|
||||
&log.Raw,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan oathkeeper log: %w", err)
|
||||
}
|
||||
}
|
||||
logs = append(logs, log)
|
||||
}
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func buildOathkeeperQuery(subject string, limit int, cursor *domain.AuditCursor, withClientID bool) (string, []any) {
|
||||
selectCols := "timestamp, request_id, method, path, status, latency_ms, rp, action, target, subject, client_ip, user_agent, decision, trace_id, span_id, raw"
|
||||
if withClientID {
|
||||
selectCols = "timestamp, request_id, method, path, status, latency_ms, client_id, rp, action, target, subject, client_ip, user_agent, decision, trace_id, span_id, raw"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("SELECT %s FROM oathkeeper_access_logs", selectCols)
|
||||
args := make([]any, 0, 5)
|
||||
if subject != "" {
|
||||
query += `
|
||||
@@ -63,39 +131,25 @@ func (r *OathkeeperClickHouseRepository) FindPageBySubject(ctx context.Context,
|
||||
LIMIT ?
|
||||
`
|
||||
args = append(args, limit)
|
||||
return query, args
|
||||
}
|
||||
|
||||
rows, err := r.conn.Query(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query oathkeeper logs: %w", err)
|
||||
func isMissingColumnError(err error, column string) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var logs []domain.OathkeeperAccessLog
|
||||
for rows.Next() {
|
||||
var log domain.OathkeeperAccessLog
|
||||
if err := rows.Scan(
|
||||
&log.Timestamp,
|
||||
&log.RequestID,
|
||||
&log.Method,
|
||||
&log.Path,
|
||||
&log.Status,
|
||||
&log.LatencyMs,
|
||||
&log.RP,
|
||||
&log.Action,
|
||||
&log.Target,
|
||||
&log.Subject,
|
||||
&log.ClientIP,
|
||||
&log.UserAgent,
|
||||
&log.Decision,
|
||||
&log.TraceID,
|
||||
&log.SpanID,
|
||||
&log.Raw,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to scan oathkeeper log: %w", err)
|
||||
}
|
||||
logs = append(logs, log)
|
||||
msg := strings.ToLower(err.Error())
|
||||
column = strings.ToLower(column)
|
||||
if strings.Contains(msg, "unknown identifier") && strings.Contains(msg, column) {
|
||||
return true
|
||||
}
|
||||
return logs, nil
|
||||
if strings.Contains(msg, "unknown expression identifier") && strings.Contains(msg, column) {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(msg, "missing columns") && strings.Contains(msg, column) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *OathkeeperClickHouseRepository) Ping(ctx context.Context) error {
|
||||
|
||||
Reference in New Issue
Block a user