forked from baron/baron-sso
feat: improve Worksmobile tenant sync handling
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
)
|
||||
|
||||
const HanmacFamilyTenantSlug = "hanmac-family"
|
||||
const worksmobileExcludedConfigKey = "worksmobileExcluded"
|
||||
|
||||
type WorksmobileSyncer interface {
|
||||
EnqueueTenantUpsertIfInScope(ctx context.Context, tenant domain.Tenant) error
|
||||
@@ -31,6 +32,7 @@ type WorksmobileAdminService interface {
|
||||
EnqueueUserSync(ctx context.Context, tenantID, userID, credentialBatchID string) (*domain.WorksmobileOutbox, error)
|
||||
EnqueueUserPasswordReset(ctx context.Context, tenantID, userID, credentialBatchID string) (*domain.WorksmobileOutbox, error)
|
||||
RetryJob(ctx context.Context, tenantID, jobID string) (*domain.WorksmobileOutbox, error)
|
||||
DeletePendingJobs(ctx context.Context, tenantID string) (WorksmobilePendingJobDeleteResult, error)
|
||||
ListInitialPasswordCredentials(ctx context.Context, tenantID, credentialBatchID string) ([]WorksmobileInitialPasswordCredential, error)
|
||||
ListCredentialBatches(ctx context.Context, tenantID string) ([]WorksmobileCredentialBatch, error)
|
||||
DeleteCredentialBatchPasswords(ctx context.Context, tenantID, credentialBatchID string) (WorksmobileCredentialBatch, error)
|
||||
@@ -54,6 +56,10 @@ type WorksmobileBackfillDryRun struct {
|
||||
UserCount int `json:"userCount"`
|
||||
}
|
||||
|
||||
type WorksmobilePendingJobDeleteResult struct {
|
||||
DeletedCount int `json:"deletedCount"`
|
||||
}
|
||||
|
||||
type WorksmobileInitialPasswordCredential struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name,omitempty"`
|
||||
@@ -178,6 +184,21 @@ func worksmobileDirectoryAuthConfigured() bool {
|
||||
strings.TrimSpace(os.Getenv("WORKS_ADMIN_OAUTH_CLIENT_PRIVATE_KEY_FILE")) != "")
|
||||
}
|
||||
|
||||
func WorksmobileExcluded(config domain.JSONMap) bool {
|
||||
rawValue, ok := config[worksmobileExcludedConfigKey]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
switch value := rawValue.(type) {
|
||||
case bool:
|
||||
return value
|
||||
case string:
|
||||
return strings.EqualFold(strings.TrimSpace(value), "true")
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func redactWorksmobileOutboxPayloads(jobs []domain.WorksmobileOutbox) []domain.WorksmobileOutbox {
|
||||
for i := range jobs {
|
||||
jobs[i].Payload = safeWorksmobileOutboxPayload(jobs[i].Payload)
|
||||
@@ -394,6 +415,9 @@ func (s *worksmobileSyncService) EnqueueOrgUnitSync(ctx context.Context, tenantI
|
||||
return nil, err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[tenant.ID]; !ok {
|
||||
return nil, errors.New("target tenant is excluded from Worksmobile sync")
|
||||
}
|
||||
if !isWorksmobileOrgUnitTenant(*tenant, tenantByID) {
|
||||
return nil, errors.New("target tenant is not a worksmobile orgunit tenant")
|
||||
}
|
||||
@@ -511,13 +535,16 @@ func (s *worksmobileSyncService) EnqueueUserSync(ctx context.Context, tenantID,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[tenant.ID]; !ok {
|
||||
return nil, errors.New("target user tenant is excluded from Worksmobile sync")
|
||||
}
|
||||
if domain.IsWorksDeprovisionUserStatus(user.Status) {
|
||||
return s.enqueueUserDelete(ctx, *user, "user:delete:"+user.ID, root.ID)
|
||||
}
|
||||
if !domain.IsWorksProvisionedUserStatus(user.Status) {
|
||||
return nil, errors.New("target user status is excluded from Worksmobile sync")
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
payload, err := BuildWorksmobileUserPayloadForDomainTenants(
|
||||
*user,
|
||||
*tenant,
|
||||
@@ -582,6 +609,9 @@ func (s *worksmobileSyncService) EnqueueUserPasswordReset(ctx context.Context, t
|
||||
return nil, err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[tenant.ID]; !ok {
|
||||
return nil, errors.New("target user tenant is excluded from Worksmobile sync")
|
||||
}
|
||||
payload, err := BuildWorksmobileUserPayloadForDomainTenants(*user, *tenant, tenantByID, root.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -722,6 +752,18 @@ func (s *worksmobileSyncService) RetryJob(ctx context.Context, tenantID, jobID s
|
||||
return s.outboxRepo.FindByID(ctx, jobID)
|
||||
}
|
||||
|
||||
func (s *worksmobileSyncService) DeletePendingJobs(ctx context.Context, tenantID string) (WorksmobilePendingJobDeleteResult, error) {
|
||||
root, err := s.hanmacRoot(ctx, tenantID)
|
||||
if err != nil {
|
||||
return WorksmobilePendingJobDeleteResult{}, err
|
||||
}
|
||||
deleted, err := s.outboxRepo.DeletePendingByTenantRoot(ctx, root.ID)
|
||||
if err != nil {
|
||||
return WorksmobilePendingJobDeleteResult{}, err
|
||||
}
|
||||
return WorksmobilePendingJobDeleteResult{DeletedCount: int(deleted)}, nil
|
||||
}
|
||||
|
||||
func (s *worksmobileSyncService) EnqueueTenantUpsertIfInScope(ctx context.Context, tenant domain.Tenant) error {
|
||||
root, ok, err := s.rootForTenant(ctx, tenant)
|
||||
if err != nil || !ok {
|
||||
@@ -732,6 +774,9 @@ func (s *worksmobileSyncService) EnqueueTenantUpsertIfInScope(ctx context.Contex
|
||||
return err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[tenant.ID]; !ok {
|
||||
return nil
|
||||
}
|
||||
if !isWorksmobileOrgUnitTenant(tenant, tenantByID) {
|
||||
return nil
|
||||
}
|
||||
@@ -767,6 +812,9 @@ func (s *worksmobileSyncService) EnqueueTenantDeleteIfInScope(ctx context.Contex
|
||||
return err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[tenant.ID]; !ok {
|
||||
return nil
|
||||
}
|
||||
if !isWorksmobileOrgUnitTenant(tenant, tenantByID) {
|
||||
return nil
|
||||
}
|
||||
@@ -795,6 +843,10 @@ func (s *worksmobileSyncService) EnqueueUserUpsertIfInScope(ctx context.Context,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[*user.TenantID]; !ok {
|
||||
return nil
|
||||
}
|
||||
if domain.IsWorksDeprovisionUserStatus(user.Status) {
|
||||
_, err := s.enqueueUserDelete(ctx, user, "user:delete:"+user.ID, root.ID)
|
||||
return err
|
||||
@@ -802,7 +854,6 @@ func (s *worksmobileSyncService) EnqueueUserUpsertIfInScope(ctx context.Context,
|
||||
if !domain.IsWorksProvisionedUserStatus(user.Status) {
|
||||
return nil
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
payload, err := BuildWorksmobileUserPayloadForDomainTenants(
|
||||
user,
|
||||
*tenant,
|
||||
@@ -833,10 +884,18 @@ func (s *worksmobileSyncService) EnqueueUserDeleteIfInScope(ctx context.Context,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, ok, err := s.rootForTenant(ctx, *tenant)
|
||||
root, ok, err := s.rootForTenant(ctx, *tenant)
|
||||
if err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
scopeTenants, err := s.hanmacSubtree(ctx, root.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tenantByID := worksmobileTenantByID(append([]domain.Tenant{*root}, scopeTenants...))
|
||||
if _, ok := tenantByID[*user.TenantID]; !ok {
|
||||
return nil
|
||||
}
|
||||
_, err = s.enqueueUserDelete(ctx, user, "user:delete:"+user.ID, "")
|
||||
return err
|
||||
}
|
||||
@@ -891,6 +950,9 @@ func (s *worksmobileSyncService) hanmacSubtree(ctx context.Context, rootID strin
|
||||
var visit func(id string)
|
||||
visit = func(id string) {
|
||||
for _, child := range byParent[id] {
|
||||
if WorksmobileExcluded(child.Config) {
|
||||
continue
|
||||
}
|
||||
result = append(result, child)
|
||||
visit(child.ID)
|
||||
}
|
||||
@@ -1011,6 +1073,9 @@ func normalizeWorksmobileSlugLocalPart(value string) string {
|
||||
}
|
||||
|
||||
func isWorksmobileOrgUnitTenant(tenant domain.Tenant, tenantByID map[string]domain.Tenant) bool {
|
||||
if isWorksmobileDomainRootTenant(tenant) {
|
||||
return false
|
||||
}
|
||||
if tenant.Type == domain.TenantTypeOrganization {
|
||||
return true
|
||||
}
|
||||
@@ -1048,12 +1113,13 @@ func worksmobileDomainClassificationTenant(tenant domain.Tenant, tenantByID map[
|
||||
func isWorksmobileDomainRootTenant(tenant domain.Tenant) bool {
|
||||
slug := strings.ToLower(strings.TrimSpace(tenant.Slug))
|
||||
switch slug {
|
||||
case "saman", "hanmac", "gpdtdc", "baron-group":
|
||||
case "saman", "hanmac", "gpdtdc", "halla", "hanlla", "baron-group":
|
||||
return true
|
||||
}
|
||||
if tenantHasDomain(tenant, "samaneng.com") ||
|
||||
tenantHasDomain(tenant, "hanmaceng.co.kr") ||
|
||||
tenantHasDomain(tenant, "baroncs.co.kr") ||
|
||||
tenantHasDomain(tenant, "hallasanup.com") ||
|
||||
tenantHasDomain(tenant, "brsw.kr") {
|
||||
return true
|
||||
}
|
||||
@@ -1061,6 +1127,7 @@ func isWorksmobileDomainRootTenant(tenant domain.Tenant) bool {
|
||||
return name == "삼안" ||
|
||||
name == "한맥기술" ||
|
||||
name == "총괄기획&기술개발센터" ||
|
||||
name == "한라산업개발" ||
|
||||
name == "바론그룹"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user