feat(epic2): Implement core authentication and authorization services
- Implement Audit Service (2.5) - gRPC server with Record and Query operations - Database persistence with audit schema - Service registry integration - Entry point: cmd/audit-service - Implement Identity Service (2.2) - User CRUD operations - Password hashing with argon2id - Email verification and password reset flows - Entry point: cmd/identity-service - Fix package naming conflicts in user_service.go - Implement Auth Service (2.1) - JWT token generation and validation - Login, RefreshToken, ValidateToken, Logout RPCs - Integration with Identity Service - Entry point: cmd/auth-service - Note: RefreshToken entity needs Ent generation - Implement Authz Service (2.3, 2.4) - Permission checking and authorization - User roles and permissions retrieval - RBAC-based authorization - Entry point: cmd/authz-service - Implement gRPC clients for all services - Auth, Identity, Authz, and Audit clients - Service discovery integration - Full gRPC communication - Add service configurations to config/default.yaml - Create SUMMARY.md with implementation details and testing instructions - Fix compilation errors in Identity Service (password package conflicts) - All services build successfully and tests pass
This commit is contained in:
125
services/audit/internal/api/server.go
Normal file
125
services/audit/internal/api/server.go
Normal file
@@ -0,0 +1,125 @@
|
||||
// Package api provides gRPC server implementation for Audit Service.
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
auditv1 "git.dcentral.systems/toolz/goplt/api/proto/generated/audit/v1"
|
||||
"git.dcentral.systems/toolz/goplt/services/audit/internal/service"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Server implements the AuditService gRPC server.
|
||||
type Server struct {
|
||||
auditv1.UnimplementedAuditServiceServer
|
||||
service *service.AuditService
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewServer creates a new Audit Service gRPC server.
|
||||
func NewServer(auditService *service.AuditService, logger *zap.Logger) *Server {
|
||||
return &Server{
|
||||
service: auditService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Record records an audit log entry.
|
||||
func (s *Server) Record(ctx context.Context, req *auditv1.RecordRequest) (*auditv1.RecordResponse, error) {
|
||||
if req.Entry == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "entry is required")
|
||||
}
|
||||
|
||||
entry := req.Entry
|
||||
|
||||
// Convert proto entry to service entry
|
||||
serviceEntry := &service.AuditLogEntry{
|
||||
UserID: entry.UserId,
|
||||
Action: entry.Action,
|
||||
Resource: entry.Resource,
|
||||
ResourceID: entry.ResourceId,
|
||||
IPAddress: entry.IpAddress,
|
||||
UserAgent: entry.UserAgent,
|
||||
Metadata: entry.Metadata,
|
||||
Timestamp: entry.Timestamp,
|
||||
}
|
||||
|
||||
// Record the audit log
|
||||
if err := s.service.Record(ctx, serviceEntry); err != nil {
|
||||
s.logger.Error("Failed to record audit log",
|
||||
zap.Error(err),
|
||||
zap.String("user_id", entry.UserId),
|
||||
zap.String("action", entry.Action),
|
||||
)
|
||||
return nil, status.Errorf(codes.Internal, "failed to record audit log: %v", err)
|
||||
}
|
||||
|
||||
return &auditv1.RecordResponse{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Query queries audit logs based on filters.
|
||||
func (s *Server) Query(ctx context.Context, req *auditv1.QueryRequest) (*auditv1.QueryResponse, error) {
|
||||
// Convert proto filters to service filters
|
||||
filters := &service.AuditLogFilters{
|
||||
Limit: int(req.Limit),
|
||||
Offset: int(req.Offset),
|
||||
}
|
||||
|
||||
if req.UserId != nil {
|
||||
userID := *req.UserId
|
||||
filters.UserID = &userID
|
||||
}
|
||||
if req.Action != nil {
|
||||
action := *req.Action
|
||||
filters.Action = &action
|
||||
}
|
||||
if req.Resource != nil {
|
||||
resource := *req.Resource
|
||||
filters.Resource = &resource
|
||||
}
|
||||
if req.ResourceId != nil {
|
||||
resourceID := *req.ResourceId
|
||||
filters.ResourceID = &resourceID
|
||||
}
|
||||
if req.StartTime != nil {
|
||||
startTime := *req.StartTime
|
||||
filters.StartTime = &startTime
|
||||
}
|
||||
if req.EndTime != nil {
|
||||
endTime := *req.EndTime
|
||||
filters.EndTime = &endTime
|
||||
}
|
||||
|
||||
// Query audit logs
|
||||
entries, err := s.service.Query(ctx, filters)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to query audit logs",
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, status.Errorf(codes.Internal, "failed to query audit logs: %v", err)
|
||||
}
|
||||
|
||||
// Convert service entries to proto entries
|
||||
protoEntries := make([]*auditv1.AuditLogEntry, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
protoEntries = append(protoEntries, &auditv1.AuditLogEntry{
|
||||
UserId: entry.UserID,
|
||||
Action: entry.Action,
|
||||
Resource: entry.Resource,
|
||||
ResourceId: entry.ResourceID,
|
||||
IpAddress: entry.IPAddress,
|
||||
UserAgent: entry.UserAgent,
|
||||
Metadata: entry.Metadata,
|
||||
Timestamp: entry.Timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
return &auditv1.QueryResponse{
|
||||
Entries: protoEntries,
|
||||
Total: int32(len(protoEntries)), // Note: This is a simplified total, actual total would require a count query
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user