forked from baron/baron-sso
chore: consolidate local integration changes
This commit is contained in:
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"baron-sso-backend/internal/domain"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@@ -30,14 +31,14 @@ type WorksmobileOrgUnitPayload struct {
|
||||
type WorksmobileUserPayload struct {
|
||||
DomainID int64 `json:"domainId"`
|
||||
Email string `json:"email"`
|
||||
UserExternalKey string `json:"userExternalKey"`
|
||||
UserExternalKey string `json:"userExternalKey,omitempty"`
|
||||
UserName WorksmobileUserName `json:"userName"`
|
||||
CellPhone string `json:"cellPhone,omitempty"`
|
||||
EmployeeNumber string `json:"employeeNumber,omitempty"`
|
||||
PrivateEmail string `json:"privateEmail,omitempty"`
|
||||
AliasEmails []string `json:"aliasEmails,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
PasswordConfig WorksmobilePasswordConfig `json:"passwordConfig"`
|
||||
PasswordConfig WorksmobilePasswordConfig `json:"passwordConfig,omitempty"`
|
||||
Task string `json:"task,omitempty"`
|
||||
Organizations []WorksmobileUserOrganization `json:"organizations,omitempty"`
|
||||
}
|
||||
@@ -47,8 +48,52 @@ type WorksmobileUserName struct {
|
||||
}
|
||||
|
||||
type WorksmobilePasswordConfig struct {
|
||||
PasswordCreationType string `json:"passwordCreationType"`
|
||||
Password string `json:"password"`
|
||||
PasswordCreationType string `json:"passwordCreationType"`
|
||||
Password string `json:"password"`
|
||||
ChangePasswordAtNextLogin *bool `json:"changePasswordAtNextLogin,omitempty"`
|
||||
}
|
||||
|
||||
func (c WorksmobilePasswordConfig) IsZero() bool {
|
||||
return strings.TrimSpace(c.PasswordCreationType) == "" &&
|
||||
strings.TrimSpace(c.Password) == "" &&
|
||||
c.ChangePasswordAtNextLogin == nil
|
||||
}
|
||||
|
||||
func (p WorksmobileUserPayload) MarshalJSON() ([]byte, error) {
|
||||
type payloadJSON struct {
|
||||
DomainID int64 `json:"domainId"`
|
||||
Email string `json:"email"`
|
||||
UserExternalKey string `json:"userExternalKey,omitempty"`
|
||||
UserName WorksmobileUserName `json:"userName"`
|
||||
CellPhone string `json:"cellPhone,omitempty"`
|
||||
EmployeeNumber string `json:"employeeNumber,omitempty"`
|
||||
PrivateEmail string `json:"privateEmail,omitempty"`
|
||||
AliasEmails []string `json:"aliasEmails,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
PasswordConfig *WorksmobilePasswordConfig `json:"passwordConfig,omitempty"`
|
||||
Task string `json:"task,omitempty"`
|
||||
Organizations []WorksmobileUserOrganization `json:"organizations,omitempty"`
|
||||
}
|
||||
|
||||
var passwordConfig *WorksmobilePasswordConfig
|
||||
if !p.PasswordConfig.IsZero() {
|
||||
passwordConfig = &p.PasswordConfig
|
||||
}
|
||||
|
||||
return json.Marshal(payloadJSON{
|
||||
DomainID: p.DomainID,
|
||||
Email: p.Email,
|
||||
UserExternalKey: p.UserExternalKey,
|
||||
UserName: p.UserName,
|
||||
CellPhone: p.CellPhone,
|
||||
EmployeeNumber: p.EmployeeNumber,
|
||||
PrivateEmail: p.PrivateEmail,
|
||||
AliasEmails: p.AliasEmails,
|
||||
Locale: p.Locale,
|
||||
PasswordConfig: passwordConfig,
|
||||
Task: p.Task,
|
||||
Organizations: p.Organizations,
|
||||
})
|
||||
}
|
||||
|
||||
type WorksmobilePasswordResetPayload struct {
|
||||
@@ -184,15 +229,11 @@ func BuildWorksmobileUserPayloadForDomainTenants(user domain.User, tenant domain
|
||||
Email: strings.TrimSpace(user.Email),
|
||||
UserExternalKey: user.ID,
|
||||
UserName: WorksmobileUserName{LastName: strings.TrimSpace(user.Name)},
|
||||
CellPhone: strings.TrimSpace(user.Phone),
|
||||
CellPhone: domain.NormalizePhoneNumber(user.Phone),
|
||||
EmployeeNumber: employeeNumber,
|
||||
Locale: "ko_KR",
|
||||
PasswordConfig: WorksmobilePasswordConfig{
|
||||
PasswordCreationType: "ADMIN",
|
||||
Password: GenerateWorksmobileInitialPassword(),
|
||||
},
|
||||
Task: task,
|
||||
Organizations: organizations,
|
||||
Task: task,
|
||||
Organizations: organizations,
|
||||
}
|
||||
payload.AliasEmails = BuildWorksmobileAliasEmails(user, tenant)
|
||||
return payload, nil
|
||||
@@ -205,12 +246,20 @@ type worksmobileAppointment struct {
|
||||
HasManager bool
|
||||
JobTitle string
|
||||
PositionID string
|
||||
Source string
|
||||
}
|
||||
|
||||
func buildWorksmobileUserOrganizations(user domain.User, tenant domain.Tenant, tenantByID map[string]domain.Tenant, rootConfig domain.JSONMap) ([]WorksmobileUserOrganization, string, error) {
|
||||
appointments := worksmobileAppointmentsFromMetadata(user.Metadata)
|
||||
if len(appointments) == 0 {
|
||||
appointments = []worksmobileAppointment{{TenantID: tenant.ID, IsPrimary: true}}
|
||||
} else if !worksmobileAppointmentsContainTenant(appointments, tenant.ID) && !worksmobileAppointmentsHavePrimary(appointments) {
|
||||
appointments = append([]worksmobileAppointment{{
|
||||
TenantID: tenant.ID,
|
||||
IsPrimary: true,
|
||||
JobTitle: strings.TrimSpace(user.JobTitle),
|
||||
PositionID: metadataString(user.Metadata, "worksmobilePositionId", "positionId", "position_id"),
|
||||
}}, appointments...)
|
||||
}
|
||||
accountDomainTenant := worksmobileAccountDomainTenantFromEmail(user.Email, tenant, tenantByID)
|
||||
accountDomainEnvKey := worksmobileTenantDomainIDEnvKey(accountDomainTenant)
|
||||
@@ -235,6 +284,17 @@ func buildWorksmobileUserOrganizations(user domain.User, tenant domain.Tenant, t
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if worksmobileShouldSkipEmailDomainRootAppointment(appointment, appointmentTenant, appointments, tenantByID) {
|
||||
seen[appointment.TenantID] = true
|
||||
continue
|
||||
}
|
||||
if isWorksmobileDomainRootTenant(appointmentTenant) {
|
||||
if appointment.IsPrimary && strings.TrimSpace(appointment.JobTitle) != "" && task == "" {
|
||||
task = strings.TrimSpace(appointment.JobTitle)
|
||||
}
|
||||
seen[appointment.TenantID] = true
|
||||
continue
|
||||
}
|
||||
if err := ValidateWorksmobileExternalKey(appointmentTenant.ID); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -276,7 +336,7 @@ func buildWorksmobileUserOrganizations(user domain.User, tenant domain.Tenant, t
|
||||
seen[appointment.TenantID] = true
|
||||
}
|
||||
if len(organizations) == 0 {
|
||||
return nil, "", errors.New("no valid worksmobile organization")
|
||||
return nil, task, nil
|
||||
}
|
||||
if !worksmobileOrganizationsHavePrimary(organizations) {
|
||||
organizations[0].Primary = true
|
||||
@@ -288,6 +348,28 @@ func buildWorksmobileUserOrganizations(user domain.User, tenant domain.Tenant, t
|
||||
return organizations, task, nil
|
||||
}
|
||||
|
||||
func worksmobileAppointmentsContainTenant(appointments []worksmobileAppointment, tenantID string) bool {
|
||||
tenantID = strings.TrimSpace(tenantID)
|
||||
if tenantID == "" {
|
||||
return false
|
||||
}
|
||||
for _, appointment := range appointments {
|
||||
if strings.TrimSpace(appointment.TenantID) == tenantID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func worksmobileAppointmentsHavePrimary(appointments []worksmobileAppointment) bool {
|
||||
for _, appointment := range appointments {
|
||||
if appointment.IsPrimary {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func worksmobileAppointmentsContainDomain(appointments []worksmobileAppointment, tenantByID map[string]domain.Tenant, envKey string) bool {
|
||||
for _, appointment := range appointments {
|
||||
tenant, ok := tenantByID[appointment.TenantID]
|
||||
@@ -302,6 +384,26 @@ func worksmobileAppointmentsContainDomain(appointments []worksmobileAppointment,
|
||||
return false
|
||||
}
|
||||
|
||||
func worksmobileShouldSkipEmailDomainRootAppointment(appointment worksmobileAppointment, tenant domain.Tenant, appointments []worksmobileAppointment, tenantByID map[string]domain.Tenant) bool {
|
||||
if strings.TrimSpace(appointment.Source) != "email_domain" || !isWorksmobileDomainRootTenant(tenant) {
|
||||
return false
|
||||
}
|
||||
envKey := worksmobileTenantDomainIDEnvKey(tenant)
|
||||
for _, candidate := range appointments {
|
||||
if strings.TrimSpace(candidate.TenantID) == "" || strings.TrimSpace(candidate.TenantID) == tenant.ID {
|
||||
continue
|
||||
}
|
||||
candidateTenant, ok := tenantByID[candidate.TenantID]
|
||||
if !ok || isWorksmobileDomainRootTenant(candidateTenant) {
|
||||
continue
|
||||
}
|
||||
if worksmobileTenantDomainIDEnvKey(worksmobileDomainClassificationTenant(candidateTenant, tenantByID)) == envKey {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func worksmobileOrganizationsHavePrimary(organizations []WorksmobileUserOrganization) bool {
|
||||
for _, organization := range organizations {
|
||||
if organization.Primary {
|
||||
@@ -327,6 +429,7 @@ func worksmobileAppointmentsFromMetadata(metadata domain.JSONMap) []worksmobileA
|
||||
IsPrimary: metadataBool(domain.JSONMap(item), "isPrimary", "primary"),
|
||||
JobTitle: metadataString(domain.JSONMap(item), "jobTitle", "job_title", "task"),
|
||||
PositionID: metadataString(domain.JSONMap(item), "worksmobilePositionId", "positionId", "position_id"),
|
||||
Source: metadataString(domain.JSONMap(item), "assignmentSource", "source"),
|
||||
}
|
||||
if isManager, ok := metadataOptionalBool(domain.JSONMap(item), "isManager", "lead", "isLead"); ok {
|
||||
appointment.IsManager = isManager
|
||||
@@ -416,7 +519,7 @@ func ValidateWorksmobileAliasEmails(primaryEmail string, aliasEmails []string, e
|
||||
func GenerateWorksmobileInitialPassword() string {
|
||||
digits := "0123456789"
|
||||
letters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
symbols := "!@#$%^&*()-_=+[]{}"
|
||||
symbols := "!@#$%"
|
||||
all := digits + letters + symbols
|
||||
|
||||
password := []byte{
|
||||
|
||||
Reference in New Issue
Block a user