1
0
forked from baron/baron-sso

custom claim 권한체크 확인

This commit is contained in:
2026-06-11 08:29:25 +09:00
parent 839ca9d407
commit 4d77060b5d
79 changed files with 4268 additions and 670 deletions

View File

@@ -0,0 +1,79 @@
package service
import (
"baron-sso-backend/internal/domain"
"context"
"encoding/json"
"fmt"
"strings"
"time"
)
type IdentityUpdateRequest struct {
IdentityID string
Traits map[string]any
State string
Reason string
Source string
}
type IdentityWriteService interface {
GetIdentity(ctx context.Context, identityID string) (*KratosIdentity, error)
UpdateIdentity(ctx context.Context, req IdentityUpdateRequest) (*KratosIdentity, error)
}
type identityWriteService struct {
kratos KratosAdminService
redis domain.RedisRepository
}
func NewIdentityWriteService(kratos KratosAdminService, redis domain.RedisRepository) IdentityWriteService {
return &identityWriteService{
kratos: kratos,
redis: redis,
}
}
func (s *identityWriteService) GetIdentity(ctx context.Context, identityID string) (*KratosIdentity, error) {
if s == nil || s.kratos == nil {
return nil, fmt.Errorf("kratos admin service is required")
}
return s.kratos.GetIdentity(ctx, identityID)
}
func (s *identityWriteService) UpdateIdentity(ctx context.Context, req IdentityUpdateRequest) (*KratosIdentity, error) {
if s == nil || s.kratos == nil {
return nil, fmt.Errorf("kratos admin service is required")
}
updated, err := s.kratos.UpdateIdentity(ctx, req.IdentityID, req.Traits, req.State)
if err != nil {
return nil, err
}
_ = s.markIdentityMirrorStale(req)
return updated, nil
}
func (s *identityWriteService) markIdentityMirrorStale(req IdentityUpdateRequest) error {
if s == nil || s.redis == nil {
return nil
}
now := time.Now().UTC()
reason := strings.TrimSpace(req.Reason)
if reason == "" {
reason = "identity_write"
}
source := strings.TrimSpace(req.Source)
if source != "" {
reason = source + ": " + reason
}
state := domain.IdentityCacheStatus{
Status: "stale",
LastError: reason,
UpdatedAt: &now,
}
raw, err := json.Marshal(state)
if err != nil {
return err
}
return s.redis.Set("identity:mirror:state", string(raw), 0)
}

View File

@@ -0,0 +1,75 @@
package service
import (
"baron-sso-backend/internal/domain"
"context"
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
type identityWriteRedisStub struct {
values map[string]string
}
func (s *identityWriteRedisStub) Set(key string, value string, expiration time.Duration) error {
if s.values == nil {
s.values = map[string]string{}
}
s.values[key] = value
return nil
}
func (s *identityWriteRedisStub) Get(key string) (string, error) {
return s.values[key], nil
}
func (s *identityWriteRedisStub) Delete(key string) error {
delete(s.values, key)
return nil
}
func (s *identityWriteRedisStub) StoreVerificationCode(phone, code string) error {
return nil
}
func (s *identityWriteRedisStub) GetVerificationCode(phone string) (string, error) {
return "", nil
}
func (s *identityWriteRedisStub) DeleteVerificationCode(phone string) error {
return nil
}
func TestIdentityWriteServiceUpdateIdentityMarksMirrorStale(t *testing.T) {
kratos := new(MockKratosAdminServiceShared)
redis := &identityWriteRedisStub{}
traits := map[string]any{"email": "user@example.com"}
kratos.On("UpdateIdentity", mock.Anything, "user-1", traits, "active").Return(&KratosIdentity{
ID: "user-1",
State: "active",
Traits: traits,
}, nil).Once()
writer := NewIdentityWriteService(kratos, redis)
updated, err := writer.UpdateIdentity(context.Background(), IdentityUpdateRequest{
IdentityID: "user-1",
Traits: traits,
State: "active",
Reason: "rp_custom_claims_sync",
Source: "dev_handler",
})
require.NoError(t, err)
require.Equal(t, "user-1", updated.ID)
rawState := redis.values["identity:mirror:state"]
require.NotEmpty(t, rawState)
var state domain.IdentityCacheStatus
require.NoError(t, json.Unmarshal([]byte(rawState), &state))
require.Equal(t, "stale", state.Status)
require.Contains(t, state.LastError, "rp_custom_claims_sync")
kratos.AssertExpectations(t)
}

View File

@@ -1031,6 +1031,12 @@ func TestCompareWorksmobileUsersIncludesWorksOnlyRowsWithoutExternalIDWhenInclud
}
func TestCompareWorksmobileGroupsIncludesBaronAndWorksParentOrg(t *testing.T) {
t.Setenv("SAMAN_DOMAIN_ID", "")
t.Setenv("HANMAC_DOMAIN_ID", "")
t.Setenv("GPDTDC_DOMAIN_ID", "")
t.Setenv("HALLA_DOMAIN_ID", "")
t.Setenv("BARONGROUP_DOMAIN_ID", "")
parentID := "tenant-parent"
childID := "tenant-child"
localTenants := []domain.Tenant{