From ffb587f9eec4342eb11ee1a70e86f5c4b41de46a Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:42:57 +0200 Subject: [PATCH] fix: sanitize primary domain for orgs (#6125) * fix: sanitize primary domain for orgs * fix: add @stebenz requested changes --------- Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> --- internal/domain/org_domain.go | 34 ++++++++++- internal/domain/org_domain_test.go | 90 ++++++++++++++++++++++++++++++ internal/org/model/org.go | 9 +-- 3 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 internal/domain/org_domain_test.go diff --git a/internal/domain/org_domain.go b/internal/domain/org_domain.go index 6009639edc..ad39e36795 100644 --- a/internal/domain/org_domain.go +++ b/internal/domain/org_domain.go @@ -1,6 +1,7 @@ package domain import ( + "regexp" "strings" http_util "github.com/zitadel/zitadel/internal/api/http" @@ -32,7 +33,38 @@ func (domain *OrgDomain) GenerateVerificationCode(codeGenerator crypto.Generator } func NewIAMDomainName(orgName, iamDomain string) string { - return strings.ToLower(strings.ReplaceAll(strings.TrimSpace(orgName), " ", "-") + "." + iamDomain) + // Reference: label domain requirements https://www.nic.ad.jp/timeline/en/20th/appendix1.html + + // Replaces spaces in org name with hyphens + label := strings.ReplaceAll(orgName, " ", "-") + + // The label must only contains alphanumeric characters and hyphens + // Invalid characters are replaced with and empty space + label = string(regexp.MustCompile(`[^a-zA-Z0-9-]`).ReplaceAll([]byte(label), []byte(""))) + + // The label cannot exceed 63 characters + if len(label) > 63 { + label = label[:63] + } + + // The total length of the resulting domain can't exceed 253 characters + domain := label + "." + iamDomain + if len(domain) > 253 { + truncateNChars := len(domain) - 253 + label = label[:len(label)-truncateNChars] + } + + // Label (maybe truncated) can't start with a hyphen + if len(label) > 0 && label[0:1] == "-" { + label = label[1:] + } + + // Label (maybe truncated) can't end with a hyphen + if len(label) > 0 && label[len(label)-1:] == "-" { + label = label[:len(label)-1] + } + + return strings.ToLower(label + "." + iamDomain) } type OrgDomainValidationType int32 diff --git a/internal/domain/org_domain_test.go b/internal/domain/org_domain_test.go new file mode 100644 index 0000000000..8dd77ca328 --- /dev/null +++ b/internal/domain/org_domain_test.go @@ -0,0 +1,90 @@ +package domain + +import ( + "testing" +) + +func TestNewIAMDomainName(t *testing.T) { + type args struct { + orgName string + iamDomain string + } + tests := []struct { + name string + args args + result string + }{ + { + name: "Single word domain is already valid", + args: args{ + orgName: "single-word-domain", + iamDomain: "localhost", + }, + result: "single-word-domain.localhost", + }, + { + name: "resulting domain should be in lowercase", + args: args{ + orgName: "Uppercase org Name", + iamDomain: "localhost", + }, + result: "uppercase-org-name.localhost", + }, + { + name: "replace spaces with hyphens", + args: args{ + orgName: "my org name", + iamDomain: "localhost", + }, + result: "my-org-name.localhost", + }, + { + name: "replace invalid characters [^a-zA-Z0-9-] with empty spaces", + args: args{ + orgName: "mí Örg name?", + iamDomain: "localhost", + }, + result: "m-rg-name.localhost", + }, + { + name: "label created from org name size is not greater than 63 chars", + args: args{ + orgName: "my organization name must not exceed sixty-three characters 1234", + iamDomain: "localhost", + }, + result: "my-organization-name-must-not-exceed-sixty-three-characters-123.localhost", + }, + { + name: "resulting domain cannot exceed 253 chars", + args: args{ + orgName: "Lorem ipsum dolor sit amet", + iamDomain: "llgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk", + }, + result: "lorem-ipsum-dolor-sit.llgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch.co.uk", + }, + { + name: "label based on org name should not end with a hyphen", + args: args{ + orgName: "my super long organization name with many many many characters ", + iamDomain: "localhost", + }, + result: "my-super-long-organization-name-with-many-many-many-characters.localhost", + }, + { + name: "label based on org name should not start with a hyphen", + args: args{ + orgName: " my super long organization name with many many many characters", + iamDomain: "localhost", + }, + result: "my-super-long-organization-name-with-many-many-many-characters.localhost", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + domain := NewIAMDomainName(tt.args.orgName, tt.args.iamDomain) + if tt.result != domain { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, domain) + } + }) + } +} diff --git a/internal/org/model/org.go b/internal/org/model/org.go index a944a6897e..4267506b58 100644 --- a/internal/org/model/org.go +++ b/internal/org/model/org.go @@ -1,8 +1,7 @@ package model import ( - "strings" - + "github.com/zitadel/zitadel/internal/domain" es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models" iam_model "github.com/zitadel/zitadel/internal/iam/model" ) @@ -46,10 +45,6 @@ func (o *Org) GetPrimaryDomain() *OrgDomain { return nil } -func (o *Org) nameForDomain(iamDomain string) string { - return strings.ToLower(strings.ReplaceAll(o.Name, " ", "-") + "." + iamDomain) -} - func (o *Org) AddIAMDomain(iamDomain string) { - o.Domains = append(o.Domains, &OrgDomain{Domain: o.nameForDomain(iamDomain), Verified: true, Primary: true}) + o.Domains = append(o.Domains, &OrgDomain{Domain: domain.NewIAMDomainName(o.Name, iamDomain), Verified: true, Primary: true}) }