forked from baron/baron-sso
feat(auth): lock affiliation type on frontend based on verified email domain (#500)
This commit is contained in:
@@ -406,6 +406,24 @@ func (h *AuthHandler) SendSignupSmsCode(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{"message": "Verification code sent"})
|
||||
}
|
||||
|
||||
var affiliateSlugs = map[string]bool{
|
||||
"hanmac": true,
|
||||
"saman": true,
|
||||
"ptc": true,
|
||||
"jangheon": true,
|
||||
"baron": true,
|
||||
"halla": true,
|
||||
}
|
||||
|
||||
func (h *AuthHandler) isAffiliateTenant(ctx context.Context, domainName string) (bool, *domain.Tenant) {
|
||||
tenant, err := h.TenantService.GetTenantByDomain(ctx, domainName)
|
||||
if err != nil || tenant == nil {
|
||||
return false, nil
|
||||
}
|
||||
// [Strict] Check if the slug belongs to the predefined family company slugs
|
||||
return affiliateSlugs[strings.ToLower(tenant.Slug)], tenant
|
||||
}
|
||||
|
||||
// VerifySignupCode - Verifies the code for email or phone
|
||||
func (h *AuthHandler) VerifySignupCode(c *fiber.Ctx) error {
|
||||
var req domain.VerifySignupCodeRequest
|
||||
@@ -459,11 +477,11 @@ func (h *AuthHandler) VerifySignupCode(c *fiber.Ctx) error {
|
||||
state.Verified = true
|
||||
h.saveSignupState(key, state, signupStateExpiration)
|
||||
|
||||
// [New] Check if this is an affiliate domain to let frontend lock the choice
|
||||
// [New] Check if this is a family affiliate domain to let frontend lock the choice
|
||||
isAffiliate := false
|
||||
parts := strings.Split(req.Target, "@")
|
||||
if req.Type == "email" && len(parts) == 2 {
|
||||
isAffiliate, _ = h.TenantService.IsDomainAllowed(c.Context(), parts[1])
|
||||
isAffiliate, _ = h.isAffiliateTenant(c.Context(), parts[1])
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
@@ -498,7 +516,14 @@ func (h *AuthHandler) GetActiveTenants(c *fiber.Ctx) error {
|
||||
if len(parts) != 2 {
|
||||
return c.JSON([]interface{}{})
|
||||
}
|
||||
domainFilter := parts[1]
|
||||
domainName := parts[1]
|
||||
|
||||
// [Policy] Verify if the email belongs to any family affiliate domain
|
||||
isInternal, _ := h.isAffiliateTenant(c.Context(), domainName)
|
||||
if !isInternal {
|
||||
// If not an affiliate email, do not show any tenants
|
||||
return c.JSON([]interface{}{})
|
||||
}
|
||||
|
||||
// 3. List and Filter Tenants
|
||||
tenants, _, err := h.TenantService.ListTenants(c.Context(), 1000, 0, "")
|
||||
@@ -516,19 +541,8 @@ func (h *AuthHandler) GetActiveTenants(c *fiber.Ctx) error {
|
||||
|
||||
var results []tenantResp
|
||||
for _, t := range tenants {
|
||||
if t.Status != domain.TenantStatusActive {
|
||||
continue
|
||||
}
|
||||
|
||||
// Strictly filter by the domain of the verified email
|
||||
match := false
|
||||
for _, d := range t.Domains {
|
||||
if strings.EqualFold(d.Domain, domainFilter) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
// [Strict] Only allow choosing defined family company slugs
|
||||
if t.Status != domain.TenantStatusActive || !affiliateSlugs[strings.ToLower(t.Slug)] {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -599,10 +613,10 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
}
|
||||
domainName := parts[1]
|
||||
|
||||
// Check if this domain is registered to ANY company
|
||||
isInternal, _ := h.TenantService.IsDomainAllowed(c.Context(), domainName)
|
||||
// Check if this domain belongs to a predefined family affiliate
|
||||
isInternal, _ := h.isAffiliateTenant(c.Context(), domainName)
|
||||
|
||||
// [Strict Policy] Force AffiliationType based on domain (User cannot choose)
|
||||
// [Strict Policy] Force AffiliationType based on predefined family slugs (User cannot choose)
|
||||
if isInternal {
|
||||
req.AffiliationType = "AFFILIATE"
|
||||
slog.Info("[Signup] Forcing AffiliationType to AFFILIATE", "email", req.Email)
|
||||
@@ -611,7 +625,7 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
slog.Info("[Signup] Forcing AffiliationType to GENERAL", "email", req.Email)
|
||||
}
|
||||
|
||||
// If user provided a CompanyCode, verify it exists and is active
|
||||
// If user provided a CompanyCode, verify it exists and is a family affiliate
|
||||
if req.CompanyCode != "" {
|
||||
// [Security] Cross-check: If domain is NOT internal, they cannot provide a CompanyCode
|
||||
if !isInternal {
|
||||
@@ -619,21 +633,16 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusForbidden, "Only affiliate members can join an organization.")
|
||||
}
|
||||
|
||||
// Verify the selected company code exists and is indeed a family company
|
||||
if !affiliateSlugs[strings.ToLower(req.CompanyCode)] {
|
||||
return errorJSON(c, fiber.StatusForbidden, "The selected organization is not a valid family affiliate.")
|
||||
}
|
||||
|
||||
tenant, err := h.TenantService.GetTenantBySlug(c.Context(), req.CompanyCode)
|
||||
if err == nil && tenant != nil {
|
||||
if tenant.Status == domain.TenantStatusActive {
|
||||
// [Security] Final domain cross-check for the selected tenant
|
||||
match := false
|
||||
for _, d := range tenant.Domains {
|
||||
if strings.EqualFold(d.Domain, domainName) {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
slog.Warn("[Signup] Domain mismatch for selected organization", "email", req.Email, "targetTenant", tenant.Slug)
|
||||
return errorJSON(c, fiber.StatusForbidden, "Your email domain does not match the selected organization.")
|
||||
}
|
||||
// We no longer strictly cross-check if the chosen tenant owns the email domain.
|
||||
// Being an 'isInternal' (family) email is enough to join ANY family affiliate.
|
||||
|
||||
slog.Info("[Signup] Assigning tenant by manual slug", "email", req.Email, "tenant", tenant.Slug)
|
||||
companyCode = tenant.Slug
|
||||
@@ -646,16 +655,12 @@ func (h *AuthHandler) Signup(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusNotFound, "The specified organization code was not found.")
|
||||
}
|
||||
} else {
|
||||
// If no CompanyCode provided but it's an internal domain, they MUST select one
|
||||
if isInternal && req.AffiliationType == "AFFILIATE" {
|
||||
// If it's a family affiliate domain, they MUST select one of the family companies
|
||||
if isInternal {
|
||||
return errorJSON(c, fiber.StatusBadRequest, "Please select your organization.")
|
||||
}
|
||||
|
||||
// If they chose GENERAL even with internal email, or it's a completely external domain
|
||||
// Here we might assign a "GENERAL" pool or a personal tenant.
|
||||
}
|
||||
|
||||
// [Strict] If no tenantID but trying to be an affiliate, it's an error
|
||||
if tenantID == nil && req.AffiliationType == "AFFILIATE" {
|
||||
return errorJSON(c, fiber.StatusBadRequest, "We couldn't verify your organization affiliation. Please check your choice.")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user