Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions api/src/services/platform_admin/realm_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ def create_realm_in_keycloak(
status_code=409,
detail=f"Domain '{normalized_domain}' is already in use.",
)

admin_parts = realm.adminEmail.strip().lower().split('@')
if len(admin_parts) != 2 or admin_parts[1] != normalized_domain:
raise HTTPException(
status_code=400,
detail=f"Admin email must belong to the '{normalized_domain}' domain.",
)

_ = self.admin.create_realm(
realm_name=realm.name,
Expand Down
7 changes: 6 additions & 1 deletion web/src/components/AdminPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { TenantForm } from './admin/TenantForm'
import { PreviewPanel } from './admin/PreviewPanel'
import { getEmailDomain, isValidEmail } from '@/lib/emailValidation'
import { isValidTenantDomain, normalizeTenantDomain } from '@/lib/tenantDomainValidation'
import { apiClient } from '../lib/api-client'
import { toast } from 'sonner'

Expand Down Expand Up @@ -47,18 +48,22 @@
return 'Failed to create tenant. Please try again.'
}

const handleSubmit = async (e: React.FormEvent) => {

Check failure on line 51 in web/src/components/AdminPanel.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=PEI-SecureLearning_core&issues=AZ0SU6ipmOedRvCF2fd0&open=AZ0SU6ipmOedRvCF2fd0&pullRequest=101
e.preventDefault()
setIsLoading(true)
try {
const normalizedDomain = domain.trim().toLowerCase()
const normalizedDomain = normalizeTenantDomain(domain)
const normalizedAdminEmail = adminEmail.trim().toLowerCase()
const isAdminEmailFormatValid = isValidEmail(normalizedAdminEmail)
const adminEmailDomain = getEmailDomain(normalizedAdminEmail) ?? ''
if (!normalizedDomain) {
toast.error('Domain is required.')
return
}
if (!isValidTenantDomain(normalizedDomain)) {
toast.error('Please provide a valid domain name.')
return
}
if (!normalizedAdminEmail || !isAdminEmailFormatValid) {
toast.error('Please provide a valid admin email.')
return
Expand Down
11 changes: 9 additions & 2 deletions web/src/components/admin/TenantFormOrganization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import RequiredAsterisk from '@/components/shared/RequiredAsterisk'
import { getEmailDomain, isValidEmail } from '@/lib/emailValidation'
import { isValidTenantDomain, normalizeTenantDomain } from '@/lib/tenantDomainValidation'

interface TenantFormOrganizationProps {
realmName: string
Expand All @@ -18,8 +19,9 @@ export function TenantFormOrganization({
adminEmail, setAdminEmail
}: Readonly<TenantFormOrganizationProps>) {

const normalizedDomain = domain.trim().toLowerCase().replace(/^@/, '').replace(/^\*\./, '')
const normalizedDomain = normalizeTenantDomain(domain)
const normalizedEmail = adminEmail.trim().toLowerCase()
const isDomainFormatValid = isValidTenantDomain(normalizedDomain)
const isAdminEmailFormatValid = !!normalizedEmail && isValidEmail(normalizedEmail)
const adminEmailDomain = getEmailDomain(normalizedEmail) ?? ''
const isAdminEmailDomainMatching =
Expand Down Expand Up @@ -48,9 +50,14 @@ export function TenantFormOrganization({
value={domain}
onChange={(e) => setDomain(e.target.value)}
className="h-10 bg-surface-subtle border-border"
aria-invalid={!normalizedDomain}
aria-invalid={!!domain.trim() && !isDomainFormatValid}
required
/>
{!!domain.trim() && !isDomainFormatValid && (
<p className="mt-1 text-xs text-destructive">
Please enter a valid domain name.
</p>
)}
</div>

<div>
Expand Down
20 changes: 20 additions & 0 deletions web/src/lib/tenantDomainValidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const DOMAIN_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;

export function normalizeTenantDomain(value: string): string {
return value.trim().toLowerCase().replace(/^@/, "").replace(/^\*\./, "");
}

export function isValidTenantDomain(value: string): boolean {
const domain = normalizeTenantDomain(value);

if (!domain || domain.length > 253 || /\s/.test(domain) || domain.includes("..")) {
return false;
}

const labels = domain.split(".");
if (labels.length < 2) {
return false;
}

return labels.every((label) => DOMAIN_LABEL_RE.test(label));
}
Loading