1
0
forked from baron/baron-sso

Consent 승인 및 해지 이벤트 감사 로그 기록

This commit is contained in:
2026-02-04 13:45:28 +09:00
parent f88b1c37cb
commit 63c9172ebc

View File

@@ -3342,6 +3342,24 @@ func (h *AuthHandler) RevokeLinkedRp(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to revoke link")
}
if h.AuditRepo != nil {
detailsMap := map[string]interface{}{
"client_id": clientID,
}
detailsBytes, _ := json.Marshal(detailsMap)
_ = h.AuditRepo.Create(&domain.AuditLog{
EventID: GenerateSecureToken(16),
Timestamp: time.Now(),
UserID: subject,
EventType: "consent.revoked",
Status: "success",
IPAddress: c.IP(),
UserAgent: string(c.Request().Header.UserAgent()),
Details: string(detailsBytes),
})
}
return c.Status(fiber.StatusOK).JSON(fiber.Map{
"status": "success",
"message": "Link revoked successfully",
@@ -3467,6 +3485,26 @@ func (h *AuthHandler) AcceptConsentRequest(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to accept consent request")
}
if h.AuditRepo != nil {
detailsMap := map[string]interface{}{
"client_id": consentRequest.Client.ClientID,
"scopes": consentRequest.RequestedScope,
"client_name": consentRequest.Client.ClientName,
}
detailsBytes, _ := json.Marshal(detailsMap)
_ = h.AuditRepo.Create(&domain.AuditLog{
EventID: GenerateSecureToken(16),
Timestamp: time.Now(),
UserID: consentRequest.Subject,
EventType: "consent.granted",
Status: "success",
IPAddress: c.IP(),
UserAgent: string(c.Request().Header.UserAgent()),
Details: string(detailsBytes),
})
}
return c.JSON(acceptResp)
}
@@ -4998,3 +5036,100 @@ func mergeScopes(current []string, next []string) []string {
}
return current
}
type rpHistoryItem struct {
ClientID string `json:"client_id"`
ClientName string `json:"client_name"`
Scopes []string `json:"scopes"`
LastApprovedAt *time.Time `json:"last_approved_at"`
LastRevokedAt *time.Time `json:"last_revoked_at"`
Status string `json:"status"`
}
func (h *AuthHandler) ListRpHistory(c *fiber.Ctx) error {
subject, err := h.resolveConsentSubject(c)
if err != nil || subject == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid session"})
}
if h.AuditRepo == nil {
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{"error": "Audit service unavailable"})
}
logs, err := h.AuditRepo.FindByUserAndEvents(c.Context(), subject, []string{"consent.granted", "consent.revoked"}, 100)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to fetch history"})
}
historyMap := make(map[string]*rpHistoryItem)
// Logs are DESC (newest first). Iterate in reverse (oldest first) to build state.
for i := len(logs) - 1; i >= 0; i-- {
log := logs[i]
details, _ := parseAuditDetails(log.Details)
clientID, _ := details["client_id"].(string)
if clientID == "" {
continue
}
item, ok := historyMap[clientID]
if !ok {
item = &rpHistoryItem{
ClientID: clientID,
Status: "unknown",
}
historyMap[clientID] = item
}
if name, ok := details["client_name"].(string); ok && name != "" {
item.ClientName = name
}
if log.EventType == "consent.granted" {
item.Status = "active"
ts := log.Timestamp
item.LastApprovedAt = &ts
if scopesRaw, ok := details["scopes"].([]interface{}); ok {
scopes := make([]string, 0, len(scopesRaw))
for _, s := range scopesRaw {
if str, ok := s.(string); ok {
scopes = append(scopes, str)
}
}
item.Scopes = scopes
}
} else if log.EventType == "consent.revoked" {
item.Status = "revoked"
ts := log.Timestamp
item.LastRevokedAt = &ts
}
}
items := make([]rpHistoryItem, 0, len(historyMap))
for _, item := range historyMap {
items = append(items, *item)
}
sort.Slice(items, func(i, j int) bool {
t1 := time.Time{}
if items[i].LastApprovedAt != nil {
t1 = *items[i].LastApprovedAt
}
if items[i].LastRevokedAt != nil && items[i].LastRevokedAt.After(t1) {
t1 = *items[i].LastRevokedAt
}
t2 := time.Time{}
if items[j].LastApprovedAt != nil {
t2 = *items[j].LastApprovedAt
}
if items[j].LastRevokedAt != nil && items[j].LastRevokedAt.After(t2) {
t2 = *items[j].LastRevokedAt
}
return t1.After(t2)
})
return c.JSON(fiber.Map{"items": items})
}