Skip to content

Conversation

Mohamed-Hacene
Copy link
Collaborator

@Mohamed-Hacene Mohamed-Hacene commented Sep 23, 2025

Summary by CodeRabbit

  • New Features

    • Admins can generate SAML service-provider keys (private key + certificate) and download the public certificate from Settings.
    • Settings UI: visible "Sign SAML authn request" checkbox with help text; Generate button and Download link gated by prerequisites.
    • Form fields to view certificate and supply a write-only private key; success message shown after generation.
    • Server-side action and proxy route added to handle generation and certificate download.
    • Added SAML-related translations.
  • Bug Fixes

    • Text inputs now honor the hidden property in forms.

Copy link
Contributor

coderabbitai bot commented Sep 23, 2025

Walkthrough

Adds SAML SP key management: backend endpoints to generate keys and download the public certificate; serializer fields for SP certificate/private key; frontend schema, UI, server action, and download proxy; tighter redirect error logging; and propagation of hidden prop in a text field component.

Changes

Cohort / File(s) Summary of Changes
Backend SAML URLs
backend/iam/sso/saml/urls.py
Adds org-scoped routes: generate-keys/GenerateSAMLKeyView and download-cert/DownloadSAMLPublicCertView.
Backend SAML views
backend/iam/sso/saml/views.py
Adds GenerateSAMLKeyView (POST: generate RSA private key + self-signed X.509 cert, persist to advanced settings) and DownloadSAMLPublicCertView (GET: return stored cert PEM as attachment). Both admin-restricted.
Serializer updates
backend/iam/sso/serializers.py
Adds sp_x509cert and write-only sp_private_key fields mapped to settings.advanced.*; updates to_representation/update logic to preserve/accept private key alongside secret.
Redirect error logging
backend/iam/sso/views.py
Replaces bare except with except Exception as e in RedirectToProviderView.post and logs provider id plus exception message before rendering failedSSO.
Frontend i18n
frontend/messages/*.json (many locales, e.g. en.json, fr.json, pl.json, tr.json, ...)
Adds SAML-related translation keys (privateKey, generateDots, samlKeysGenerated, samlPrivateKeyHelpText, samlCertificateHelpText, samlAuthnRequestSignedHelpText, downloadCertificate) across locales; minor trailing-comma adjustments in some files.
Frontend SAML form UI
frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte
Adds isGenerating, handleGenerateKeys, generate button (guarded by prerequisites), download anchor, textarea fields for sp_x509cert and sp_private_key, and binding to cached form state.
Frontend field component
frontend/src/lib/components/Forms/TextField.svelte
Propagates hidden prop to the root container so the component honors the hidden flag.
Frontend schema
frontend/src/lib/utils/schemas.ts
Extends SSOSettingsSchema with optional sp_x509cert and sp_private_key string fields.
Frontend server action
frontend/src/routes/(app)/(internal)/settings/+page.server.ts
Adds generateSamlKeys action that POSTs to backend /accounts/saml/0/generate-keys/, returns generated cert or fails with 500 and surfaces a success flash message on success.
Frontend download proxy route
frontend/src/routes/(app)/(internal)/settings/saml/download-cert/+server.ts
New GET handler that proxies backend /accounts/saml/0/download-cert/ and returns PEM as attachment saml-public-cert.pem (400 on fetch failure).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Admin as Admin User
  participant UI as SsoSettingForm (Browser)
  participant SK as SvelteKit Server (actions/routes)
  participant API as Backend SAML API
  participant GS as GlobalSettings (Persistence)

  Admin->>UI: Click "Generate..." (enhanced form)
  UI->>SK: POST action generateSamlKeys
  SK->>API: POST /accounts/saml/0/generate-keys/
  API->>API: generate RSA key & self-signed X.509 cert
  API->>GS: persist settings.advanced.private_key & x509cert
  API-->>SK: 200 { cert PEM }
  SK-->>UI: return generatedKeys.cert
  UI->>UI: update sp_x509cert, clear isGenerating

  Admin->>UI: Click "Download certificate"
  UI->>SK: GET /settings/saml/download-cert
  SK->>API: GET /accounts/saml/0/download-cert/
  API-->>SK: 200 PEM text
  SK-->>Admin: attachment saml-public-cert.pem
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

High Value, i18n

Suggested reviewers

  • eric-intuitem
  • ab-smith

Poem

A rabbit forged two keys at dawn,
One private tucked where roots are drawn,
One public bright to share and send,
A PEM to give a trusted friend.
Hop — generate, then download again. 🐇🔐

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title mentions adding SSO authentication request signature support but does not capture the significant additions of key generation and certificate download endpoints and related API and UI changes. While it refers to a real aspect of the changeset, it overlooks the main feature of certificate and key management.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/sso-improvments

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Mohamed-Hacene Mohamed-Hacene changed the title Feat/sso improvments feat: add sso authentification request signature Sep 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (10)
frontend/src/lib/components/Forms/TextField.svelte (2)

118-123: Label “for” doesn’t match the input id (a11y/click-to-focus).

Associate the label with the actual input id.

Apply this diff:

-               <label class="text-sm font-semibold" for={field}
+               <label class="text-sm font-semibold" for={"form-input-" + field.replaceAll('_', '-')}
...
-               <label class="text-sm font-semibold" for={field}>{label}</label>
+               <label class="text-sm font-semibold" for={"form-input-" + field.replaceAll('_', '-')}>{label}</label>

147-149: Option: disable inputs when hidden to avoid submitting hidden fields.

If hidden fields shouldn’t be posted, gate disabled by hidden as well.

Apply this diff:

-                {disabled}
+                disabled={disabled || hidden}

Do this in both input blocks.

Also applies to: 162-164

frontend/src/lib/utils/schemas.ts (1)

484-485: Validate PEM formats and ensure private key is write‑only end‑to‑end

Consider validating expected PEM envelopes and confirm the backend never returns the private key on read endpoints (keep it write‑only). Suggested schema tweak:

-	sp_x509cert: z.string().optional(),
-	sp_private_key: z.string().optional(),
+	sp_x509cert: z
+		.string()
+		.optional()
+		.refine(
+			(val) =>
+				!val ||
+				(val.includes('-----BEGIN CERTIFICATE-----') &&
+					val.includes('-----END CERTIFICATE-----')),
+			{ message: 'Must be a PEM certificate' }
+		),
+	sp_private_key: z
+		.string()
+		.optional()
+		.refine(
+			(val) =>
+				!val ||
+				(val.includes('-----BEGIN PRIVATE KEY-----') ||
+					val.includes('-----BEGIN RSA PRIVATE KEY-----')),
+			{ message: 'Must be a PEM private key' }
+		),

Also verify SSOSettingsWriteSerializer marks sp_private_key as write_only, and that /settings/sso/object/ never includes it.

frontend/src/routes/(app)/(internal)/settings/+page.server.ts (1)

181-193: Harden error handling and avoid hard‑coded org slug

  • Propagate backend status/message to aid debugging.
  • Avoid hard‑coding "0" if multi‑org is possible (derive slug from context when available).
-  const response = await event.fetch(`${BASE_API_URL}/accounts/saml/0/generate-keys/`, {
+  const response = await event.fetch(`${BASE_API_URL}/accounts/saml/0/generate-keys/`, {
     method: 'POST'
   });
 
-  if (!response.ok) return fail(500, { error: 'Generation failed' });
+  if (!response.ok) {
+    let msg = 'Generation failed';
+    try {
+      const body = await response.json();
+      msg = body?.message ?? msg;
+    } catch {
+      try { msg = await response.text(); } catch {}
+    }
+    return fail(response.status, { error: msg });
+  }
frontend/src/routes/(app)/(internal)/settings/saml/download-cert/+server.ts (1)

6-21: Fix trailing slash and propagate backend status

  • Backend route ends with a trailing slash; avoid 301s.
  • Bubble up real status code on failure.
- const endpoint = `${BASE_API_URL}/accounts/saml/0/download-cert`;
+ const endpoint = `${BASE_API_URL}/accounts/saml/0/download-cert/`;
 
 const res = await fetch(endpoint);
-if (!res.ok) {
-  error(400, 'Error fetching the cert');
-}
+if (!res.ok) error(res.status, 'Error fetching the cert');
frontend/messages/en.json (1)

2210-2216: Minor copy tweaks (consistency/typo)

  • “Saml” → “SAML”
  • Optional: unify casing (“Private key” vs “x509 certificate” already lowercase).
-  "samlKeysGenerated": "Saml keys successfully generated",
+  "samlKeysGenerated": "SAML keys successfully generated",
frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte (3)

46-63: Use isGenerating to prevent double submissions

You set isGenerating but don’t use it to gate the button. Optional UX improvement:

- return async ({ result, update }) => {
+ return async ({ result, update }) => {
     isGenerating = false;

And on the button:

-  disabled={!data.is_enabled || !data.authn_request_signed}
+  disabled={!data.is_enabled || !data.authn_request_signed || isGenerating}

391-396: Fix download link path

The href is likely double‑prefixing “settings”. Use an absolute or a path relative to the settings page.

-  <Anchor
-    href="settings/saml/download-cert"
+  <Anchor
+    href="/settings/saml/download-cert"
     class="anchor text-secondary-500"

401-417: Gate fields on reactive form state (optional)

The disabled state uses the initial data prop. Consider deriving from form state so toggling checkboxes immediately enables these fields without reload.

backend/iam/sso/serializers.py (1)

215-221: Preserve PEM formatting and clarify SP cert intent.

Avoid trimming PEMs and add help_text to reduce confusion with IdP x509cert.

-    sp_x509cert = serializers.CharField(
-        required=False,
-        allow_blank=True,
-        allow_null=True,
-        source="settings.advanced.x509cert",
-    )
+    sp_x509cert = serializers.CharField(
+        required=False,
+        allow_blank=True,
+        allow_null=True,
+        trim_whitespace=False,
+        source="settings.advanced.x509cert",
+        help_text="SP public X.509 certificate (PEM). Stored at settings.advanced.x509cert; distinct from IdP x509cert.",
+    )

Question: Do we really want allow_blank=True here? If clearing should be explicit, prefer allow_blank=False and allow_null=True.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 400d468 and 217c600.

📒 Files selected for processing (10)
  • backend/iam/sso/saml/urls.py (1 hunks)
  • backend/iam/sso/saml/views.py (3 hunks)
  • backend/iam/sso/serializers.py (2 hunks)
  • backend/iam/sso/views.py (1 hunks)
  • frontend/messages/en.json (1 hunks)
  • frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte (3 hunks)
  • frontend/src/lib/components/Forms/TextField.svelte (1 hunks)
  • frontend/src/lib/utils/schemas.ts (1 hunks)
  • frontend/src/routes/(app)/(internal)/settings/+page.server.ts (1 hunks)
  • frontend/src/routes/(app)/(internal)/settings/saml/download-cert/+server.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
frontend/src/routes/(app)/(internal)/settings/saml/download-cert/+server.ts (1)
frontend/src/lib/utils/constants.ts (1)
  • BASE_API_URL (4-8)
backend/iam/sso/saml/urls.py (1)
backend/iam/sso/saml/views.py (2)
  • GenerateSAMLKeyView (214-278)
  • DownloadSAMLPublicCertView (281-294)
frontend/src/routes/(app)/(internal)/settings/+page.server.ts (1)
frontend/src/lib/utils/constants.ts (1)
  • BASE_API_URL (4-8)
backend/iam/sso/serializers.py (2)
backend/iam/sso/saml/views.py (1)
  • get (284-294)
backend/iam/sso/models.py (1)
  • get (58-62)
backend/iam/sso/saml/views.py (3)
backend/core/permissions.py (1)
  • IsAdministrator (57-61)
backend/iam/sso/models.py (4)
  • SSOSettings (70-124)
  • get (58-62)
  • get_provider (122-124)
  • save (115-116)
backend/global_settings/models.py (1)
  • Names (13-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build_community_frontend
  • GitHub Check: build_enterprise_frontend
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: build (3.12)
🔇 Additional comments (4)
frontend/src/lib/components/Forms/TextField.svelte (1)

114-114: Propagating hidden to the wrapper — LGTM.

This correctly honors the component’s hidden prop.

backend/iam/sso/views.py (1)

39-41: Better error handling/logs for provider redirect

Catches exceptions and logs provider id; good improvement.

backend/iam/sso/saml/urls.py (1)

21-30: Routes for key generation and cert download look good

Paths and names are consistent with the views; no concerns.

backend/iam/sso/saml/views.py (1)

261-271: Ensure private key never leaks via read endpoints

You’re storing advanced_settings["private_key"]. Confirm serializers and any “object”/read endpoints never serialize this field.

@Mohamed-Hacene Mohamed-Hacene removed the request for review from nas-tabchiche September 23, 2025 09:51
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte (3)

383-389: Prevent double-submit: wire up isGenerating to the button.

Leverage isGenerating to disable the button and set aria-busy.

Apply this diff:

-              <button
-                type="submit"
-                disabled={!data.is_enabled || !data.authn_request_signed}
-                class="btn preset-filled-secondary-500">{m.generateDots()}</button
-              >
+              <button
+                type="submit"
+                disabled={!data.is_enabled || !data.authn_request_signed || isGenerating}
+                aria-busy={isGenerating}
+                class="btn preset-filled-secondary-500"
+              >
+                {m.generateDots()}
+              </button>

401-419: Avoid browser storing/“correcting” certs and private keys.

Disable autocomplete/spellcheck on these sensitive multiline fields.

Apply this diff:

               <TextArea
                 {form}
                 field="sp_x509cert"
                 label={m.x509Cert()}
                 helpText={m.samlCertificateHelpText()}
                 disabled={!data.is_enabled || !data.authn_request_signed}
                 cacheLock={cacheLocks['sp_x509cert']}
                 bind:cachedValue={formDataCache['sp_x509cert']}
+                autocomplete="off"
+                spellcheck={false}
               />
               <TextArea
                 {form}
                 field="sp_private_key"
                 label={m.privateKey()}
                 helpText={m.samlPrivateKeyHelpText()}
                 disabled={!data.is_enabled || !data.authn_request_signed}
                 cacheLock={cacheLocks['sp_private_key']}
                 bind:cachedValue={formDataCache['sp_private_key']}
+                autocomplete="off"
+                spellcheck={false}
               />

386-398: Consider gating by form values instead of initial data for better UX.

Disabling controls based on data.* means users must save + reload before generating/downloading. Consider using the live form store instead (e.g., $form.form.is_enabled / $form.form.authn_request_signed).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 217c600 and 710446a.

📒 Files selected for processing (1)
  • frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build_enterprise_frontend
  • GitHub Check: build_community_frontend
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: build (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: Analyze (python)
🔇 Additional comments (4)
frontend/src/lib/components/Forms/ModelForm/SsoSettingForm.svelte (4)

374-381: Good call: exposing and gating AuthnRequest signing toggle with helpful copy.

This makes the prerequisites explicit and reduces misconfigurations.


46-51: Pre-submit guard is correct.

Canceling the action when prerequisites aren’t met avoids unnecessary requests.

Please confirm the server action expects the prerequisite to be persisted; otherwise we could allow client-side generation once the box is ticked (using form values) and save afterward.


370-419: i18n keys present — no action needed
Keys samlAuthnRequestSignedHelpText, downloadCertificate, samlCertificateHelpText, samlPrivateKeyHelpText, generateDots are defined in frontend/messages/en.json (lines 2211–2216).


53-61: generateSamlKeys action exists and returns cert — no action required.
Found in frontend/src/routes/(app)/(internal)/settings/+page.server.ts; it returns { generatedKeys: { cert } } and the SsoSettingForm handler only uses generatedKeys.cert.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
backend/iam/sso/saml/views.py (2)

222-229: Use DRF request.data and validate 'days' input to avoid crashes/abuse.

  • Avoid manual json.loads; DRF already parses payloads.
  • Validate and clamp 'days' to a sane range to prevent invalid certs or overflow.

Apply:

-    def post(self, request, organization_slug):
-        try:
-            data = json.loads(request.body)
-        except json.JSONDecodeError:
-            data = {}
-        cn = data.get("common_name", "saml-sp.example.com")
-        days = int(data.get("days", 365))
+    def post(self, request, organization_slug):
+        data = getattr(request, "data", {}) or {}
+        cn = data.get("common_name") or "saml-sp.example.com"
+        days_raw = data.get("days", 365)
+        try:
+            days = int(days_raw)
+        except (TypeError, ValueError):
+            return Response({"detail": "Invalid 'days' value"}, status=status.HTTP_400_BAD_REQUEST)
+        if not (1 <= days <= 3650):
+            return Response({"detail": "'days' must be between 1 and 3650"}, status=status.HTTP_400_BAD_REQUEST)

237-251: Harden certificate: clock skew + key usage/basic constraints.

Add standard X.509 extensions and pad not_valid_before to tolerate clock skew. 2048‑bit RSA is acceptable; consider 3072 for long‑lived deployments.

         cert = (
             x509.CertificateBuilder()
             .subject_name(subject)
             .issuer_name(issuer)
             .public_key(key.public_key())
             .serial_number(x509.random_serial_number())
-            .not_valid_before(datetime.utcnow())
+            .not_valid_before(datetime.utcnow() - timedelta(minutes=5))
             .not_valid_after(datetime.utcnow() + timedelta(days=days))
+            .add_extension(
+                x509.BasicConstraints(ca=False, path_length=None),
+                critical=True,
+            )
+            .add_extension(
+                x509.SubjectKeyIdentifier.from_public_key(key.public_key()),
+                critical=False,
+            )
+            .add_extension(
+                x509.AuthorityKeyIdentifier.from_issuer_public_key(key.public_key()),
+                critical=False,
+            )
+            .add_extension(
+                x509.KeyUsage(
+                    digital_signature=True,
+                    content_commitment=True,  # nonRepudiation
+                    key_encipherment=False,
+                    data_encipherment=False,
+                    key_agreement=False,
+                    key_cert_sign=False,
+                    crl_sign=False,
+                    encipher_only=False,
+                    decipher_only=False,
+                ),
+                critical=True,
+            )
             .sign(private_key=key, algorithm=hashes.SHA256())
         )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 710446a and 02601c9.

📒 Files selected for processing (2)
  • backend/iam/sso/saml/views.py (3 hunks)
  • backend/iam/sso/serializers.py (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
backend/iam/sso/saml/views.py (3)
backend/core/permissions.py (1)
  • IsAdministrator (57-61)
backend/iam/sso/models.py (4)
  • SSOSettings (70-124)
  • get (58-62)
  • get_provider (122-124)
  • save (115-116)
backend/global_settings/models.py (1)
  • Names (13-16)
backend/iam/sso/serializers.py (1)
backend/iam/sso/saml/views.py (1)
  • get (284-294)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build_enterprise_frontend
  • GitHub Check: build_community_frontend
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: build (3.12)
  • GitHub Check: test (3.12)
🔇 Additional comments (6)
backend/iam/sso/saml/views.py (3)

12-15: Correct CSRF import source.

Importing csrf_exempt from django.views.decorators.csrf is correct. Thanks for fixing the earlier crash risk.


214-221: Good: Key generation endpoint is no longer CSRF‑exempt.

Keeping CSRF protection on this admin‑only, state‑changing endpoint is the right call.


281-294: Download cert endpoint looks good.

404 on missing cert, correct content type, and attachment filename are appropriate.

backend/iam/sso/serializers.py (3)

215-220: LGTM: Adds SP cert field on advanced settings.

Field wiring and null/blank allowances look good.


221-228: Private key field: mark as sensitive in UI and docs.

Add help_text and password-style input; keep PEM intact (no trimming) which you already set.

     sp_private_key = serializers.CharField(
         required=False,
         allow_blank=True,
         allow_null=True,
         trim_whitespace=False,
         source="settings.advanced.private_key",
         write_only=True,
+        help_text="SP private key (PEM). Write-only; do not log or expose.",
+        style={"input_type": "password"},
     )

244-257: Fix KeyError and prevent accidental wiping of SP cert/key on partial updates.

Current code assumes nested dicts exist and can overwrite with empty strings.

Apply:

-        # Use stored secret and sp_private_key if no transmitted
-        validated_data["secret"] = validated_data.get(
-            "secret", settings_object.value.get("secret", "")
-        )
-        validated_data["settings"]["advanced"]["private_key"] = (
-            validated_data.get("settings", {})
-            .get("advanced", {})
-            .get(
-                "private_key",
-                settings_object.value.get("settings", {})
-                .get("advanced", {})
-                .get("private_key", ""),
-            )
-        )
+        # Use stored secret, SP private_key, and SP x509cert if not transmitted
+        validated_data["secret"] = validated_data.get(
+            "secret", settings_object.value.get("secret", "")
+        )
+        settings_data = validated_data.setdefault("settings", {})
+        advanced_data = settings_data.setdefault("advanced", {})
+        if "private_key" not in advanced_data:
+            advanced_data["private_key"] = (
+                settings_object.value.get("settings", {})
+                .get("advanced", {})
+                .get("private_key", "")
+            )
+        if "x509cert" not in advanced_data:
+            advanced_data["x509cert"] = (
+                settings_object.value.get("settings", {})
+                .get("advanced", {})
+                .get("x509cert", "")
+            )

Also, avoid storing the private key in plaintext; prefer an encrypted store.

@nas-tabchiche nas-tabchiche changed the title feat: add sso authentification request signature feat: add sso authentication request signature Sep 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
backend/iam/sso/saml/views.py (7)

222-229: Harden input parsing and validation for days/common_name.

Use DRF’s request.data and clamp days to sane bounds; avoid ValueError on non‑int.

Apply:

-        try:
-            data = json.loads(request.body)
-        except json.JSONDecodeError:
-            data = {}
-        cn = data.get("common_name", "saml-sp.example.com")
-        days = int(data.get("days", 365))
+        data = getattr(request, "data", None)
+        if not isinstance(data, dict):
+            try:
+                data = json.loads(request.body)
+            except json.JSONDecodeError:
+                data = {}
+        cn = (data.get("common_name") or "saml-sp.example.com").strip()
+        try:
+            days = int(data.get("days", 365))
+        except (TypeError, ValueError):
+            days = 365
+        days = max(1, min(days, 3650))

230-235: Optional: consider 3072‑bit keys.

Bump RSA key_size to 3072 for stronger baseline (still widely compatible).

-            key_size=2048,
+            key_size=3072,

237-251: Add minimal X.509 extensions (usage + constraints).

Helps relying parties and tooling validate intended use.

         cert = (
             x509.CertificateBuilder()
             .subject_name(subject)
             .issuer_name(issuer)
             .public_key(key.public_key())
             .serial_number(x509.random_serial_number())
             .not_valid_before(datetime.utcnow())
             .not_valid_after(datetime.utcnow() + timedelta(days=days))
+            .add_extension(
+                x509.BasicConstraints(ca=False, path_length=None), critical=True
+            )
+            .add_extension(
+                x509.KeyUsage(
+                    digital_signature=True,
+                    content_commitment=False,
+                    key_encipherment=False,
+                    data_encipherment=False,
+                    key_agreement=False,
+                    key_cert_sign=False,
+                    crl_sign=False,
+                    encipher_only=False,
+                    decipher_only=False,
+                ),
+                critical=True,
+            )
+            .add_extension(
+                x509.SubjectKeyIdentifier.from_public_key(key.public_key()),
+                critical=False,
+            )
             .sign(private_key=key, algorithm=hashes.SHA256())
         )

253-257: Prefer PKCS#8 for private key serialization.

PKCS#8 is broadly expected and future‑proof.

-        private_key_pem = key.private_bytes(
+        private_key_pem = key.private_bytes(
             encoding=serialization.Encoding.PEM,
-            format=serialization.PrivateFormat.TraditionalOpenSSL,
+            format=serialization.PrivateFormat.PKCS8,
             encryption_algorithm=serialization.NoEncryption(),
         )

261-266: Handle provider lookup failures.

Wrap get_provider to return 404 on invalid organization_slug.

-        provider = self.get_provider(organization_slug)
+        try:
+            provider = self.get_provider(organization_slug)
+        except Exception as e:
+            logger.error("Could not get provider", exc_info=e)
+            return Response({"detail": "SSO provider not found"}, status=status.HTTP_404_NOT_FOUND)

286-289: Prefer DRF Response for 404.

Minor consistency tweak with APIView.

-        if not cert_pem:
-            return HttpResponse(status=404)
+        if not cert_pem:
+            return Response(status=status.HTTP_404_NOT_FOUND)

290-294: Improve download UX: include org in filename.

Small polish only.

-        response["Content-Disposition"] = (
-            'attachment; filename="ciso-saml-public-cert.pem"'
-        )
+        filename = f'ciso-saml-public-cert-{organization_slug}.pem'
+        response["Content-Disposition"] = f'attachment; filename="{filename}"'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02601c9 and 6175942.

📒 Files selected for processing (1)
  • backend/iam/sso/saml/views.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/iam/sso/saml/views.py (3)
backend/core/permissions.py (1)
  • IsAdministrator (57-61)
backend/iam/sso/models.py (4)
  • SSOSettings (70-124)
  • get (58-62)
  • get_provider (122-124)
  • save (115-116)
backend/global_settings/models.py (1)
  • Names (13-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Analyze (python)
  • GitHub Check: enterprise-startup-docker-compose-test
  • GitHub Check: enterprise-startup-functional-test (3.12)
  • GitHub Check: startup-docker-compose-test
  • GitHub Check: startup-functional-test (3.12)
  • GitHub Check: test (3.12)
  • GitHub Check: build_enterprise_frontend
  • GitHub Check: build_community_frontend
  • GitHub Check: build (3.12)
🔇 Additional comments (4)
backend/iam/sso/saml/views.py (4)

13-13: Fixed: correct csrf_exempt import.

Now importing csrf_exempt from django.views.decorators.csrf. Good catch.


214-221: Good: key generation view is not CSRF‑exempt.

Admin‑only, state‑changing endpoint remains protected by CSRF.


261-271: Plaintext private key at rest; and potential KeyError/overwrite of advanced.

  • Storing PEM in GlobalSettings JSON is plaintext-at-rest; high‑impact secret risk.
  • Direct assignment can KeyError if keys missing and overwrites other advanced settings.

Address storage with an encrypted field or external secret store; minimally, do not persist the private key in plaintext. Also make the update safe/merge:

-        provider = self.get_provider(organization_slug)
+        provider = self.get_provider(organization_slug)
         # Retrieves the 'advanced' dictionary, or creates it if it doesn't exist
         advanced_settings = provider.app.settings.get("advanced", {})
-        advanced_settings["private_key"] = private_key_pem.decode("utf-8")
+        # TODO: Avoid persisting plaintext private keys. Prefer a secret store or encryption at rest.
+        # advanced_settings["private_key"] = <store a reference/encrypted value instead>
         advanced_settings["x509cert"] = cert_pem.decode("utf-8")
 
-        # Re-injects the dict into the application configuration
-        settings = GlobalSettings.objects.get(name=GlobalSettings.Names.SSO)
-        settings.value["settings"]["advanced"] = advanced_settings
-        settings.save()
+        # Re-injects the dict into the application configuration (defensive + merge)
+        settings = GlobalSettings.objects.get(name=GlobalSettings.Names.SSO)
+        value = settings.value or {}
+        settings_dict = value.setdefault("settings", {})
+        advanced = settings_dict.setdefault("advanced", {})
+        advanced.update(advanced_settings)
+        settings.value = value
+        settings.save()

261-266: No change needed — backend consistently uses 'private_key'

Serializers (backend/iam/sso/serializers.py) and views (backend/iam/sso/saml/views.py) read/write settings.advanced.private_key and x509cert; frontend maps sp_private_key/sp_x509cert — naming is consistent.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (3)
frontend/messages/uk.json (1)

1491-1494: Ensure SAML acronym stays uppercase in the translation

Let’s keep the SAML acronym capitalized for consistency with the rest of the i18n set and the official abbreviation.

-	"samlKeysGenerated": "Saml ключі успішно згенеровані",
+	"samlKeysGenerated": "SAML-ключі успішно згенеровані",
-	"samlAuthnRequestSignedHelpText": "Коли увімкнено, запит на аутентифікацію SAML підписується приватним ключем нижче. Відповідний публічний сертифікат надсилається постачальнику ідентифікації, щоб він міг перевірити підпис.",
+	"samlAuthnRequestSignedHelpText": "Коли увімкнено, запит на аутентифікацію SAML підписується приватним ключем нижче. Відповідний публічний сертифікат надсилається постачальнику ідентифікації, щоб він міг перевірити підпис.",
frontend/messages/de.json (1)

981-981: Update wording for the in-progress label

“Generiere...” sounds like an imperative/1st-person form and reads off compared to the rest of the formal UI copy. Prefer the neutral progressive style used elsewhere, e.g. “Generieren...” or “Wird generiert...”.

frontend/messages/hi.json (1)

949-949: Align terminology for “certificate”

Elsewhere we translate certificate as “प्रमाणपत्र” (see Line 624). Reusing the same term here keeps messaging uniform.

-	"downloadCertificate": "सर्टिफिकेट डाउनलोड करें"
+	"downloadCertificate": "प्रमाणपत्र डाउनलोड करें"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f3d513 and cfd00ae.

📒 Files selected for processing (20)
  • frontend/messages/ar.json (1 hunks)
  • frontend/messages/cs.json (1 hunks)
  • frontend/messages/da.json (1 hunks)
  • frontend/messages/de.json (1 hunks)
  • frontend/messages/el.json (1 hunks)
  • frontend/messages/es.json (1 hunks)
  • frontend/messages/fr.json (1 hunks)
  • frontend/messages/hi.json (1 hunks)
  • frontend/messages/hr.json (1 hunks)
  • frontend/messages/hu.json (1 hunks)
  • frontend/messages/id.json (1 hunks)
  • frontend/messages/it.json (1 hunks)
  • frontend/messages/nl.json (1 hunks)
  • frontend/messages/pl.json (1 hunks)
  • frontend/messages/pt.json (1 hunks)
  • frontend/messages/ro.json (1 hunks)
  • frontend/messages/sv.json (1 hunks)
  • frontend/messages/tr.json (1 hunks)
  • frontend/messages/uk.json (1 hunks)
  • frontend/messages/ur.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (python)
🔇 Additional comments (7)
frontend/messages/hr.json (1)

2203-2210: Croatian additions look solid.

The newly added SAML/help-text strings read naturally and align with the English intent. No issues spotted.

frontend/messages/pl.json (1)

1717-1717: Fix Polish grammar in SAML success toast

UI currently shows “Klucze SAML pomyślnie wygenerowane”, which is ungrammatical in Polish. Please switch to a full clause (e.g. “Klucze SAML zostały pomyślnie wygenerowane”), matching the style used elsewhere.

Apply this diff to correct the wording:

-	"samlKeysGenerated": "Klucze SAML pomyślnie wygenerowane",
+	"samlKeysGenerated": "Klucze SAML zostały pomyślnie wygenerowane",

Likely an incorrect or invalid review comment.

frontend/messages/nl.json (1)

979-979: Fix incorrect “Alleen-schrijven” wording

The help text now tells Dutch users the field is “write-only,” which reverses the intended guidance (“read-only”) and risks misconfiguration. Please switch it to “Alleen-lezen”.

-	"samlPrivateKeyHelpText": "Alleen-schrijven: gebruik dit veld alleen als u uw eigen privésleutel/certificaat moet opgeven. Anders genereert de applicatie het.",
+	"samlPrivateKeyHelpText": "Alleen-lezen: gebruik dit veld alleen als u uw eigen privésleutel/certificaat moet opgeven. Anders genereert de applicatie het.",

Likely an incorrect or invalid review comment.

frontend/messages/cs.json (1)

961-968: Czech SAML strings are aligned with the new UI flows

The added keys mirror the English source (labels, spinner text, and help messages) and keep terminology consistent with the existing SSO wording in this locale. Looks good to ship.

frontend/messages/fr.json (1)

2141-2149: French localisation update is accurate

Renaming “Versions associées” to “Révisions associées” better reflects the feature, and the newly added SAML-related strings reuse established terminology, keeping the advanced settings copy coherent. 👍

frontend/messages/pt.json (1)

971-978: Portuguese strings stay true to the English intent

The spinner text, success toast, and help messages read naturally in PT-BR and align with the backend SAML key-generation workflow. No issues from my side.

frontend/messages/da.json (1)

1253-1260: Translations align with new SSO flow copy

The new Danish strings read naturally and stay consistent with the tone used across existing SSO/SAML messaging. No issues spotted.

Comment on lines +945 to +947
"samlPrivateKeyHelpText": "كتابة فقط: استخدم هذا الحقل فقط إذا كنت بحاجة إلى تقديم مفتاح/شهادة خاص بك. خلاف ذلك، سيقوم التطبيق بإنشائه.",
"samlCertificateHelpText": "يمكنك تحديد شهادتك الخاصة أو السماح للتطبيق بإنشائها.",
"samlAuthnRequestSignedHelpText": "عند التمكين، يتم توقيع طلب المصادقة SAML بالمفتاح الخاص أدناه. يتم إرسال الشهادة العامة المقابلة إلى موفر الهوية حتى يتمكن من التحقق من التوقيع.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix incorrect translation of “write-protected”.

كتابة فقط means “write-only”, which inverts the intent of the English string (“Read-only / write-protected”). This will mislead admins configuring SAML. Please update it to convey “للقراءة فقط” (or equivalent) before shipping.

-"samlPrivateKeyHelpText": "كتابة فقط: استخدم هذا الحقل فقط إذا كنت بحاجة إلى تقديم مفتاح/شهادة خاص بك. خلاف ذلك، سيقوم التطبيق بإنشائه.",
+"samlPrivateKeyHelpText": "للقراءة فقط: استخدم هذا الحقل فقط إذا كنت بحاجة إلى تقديم مفتاح/شهادة خاص بك. خلاف ذلك، سيقوم التطبيق بإنشائه.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"samlPrivateKeyHelpText": "كتابة فقط: استخدم هذا الحقل فقط إذا كنت بحاجة إلى تقديم مفتاح/شهادة خاص بك. خلاف ذلك، سيقوم التطبيق بإنشائه.",
"samlCertificateHelpText": "يمكنك تحديد شهادتك الخاصة أو السماح للتطبيق بإنشائها.",
"samlAuthnRequestSignedHelpText": "عند التمكين، يتم توقيع طلب المصادقة SAML بالمفتاح الخاص أدناه. يتم إرسال الشهادة العامة المقابلة إلى موفر الهوية حتى يتمكن من التحقق من التوقيع.",
"samlPrivateKeyHelpText": "للقراءة فقط: استخدم هذا الحقل فقط إذا كنت بحاجة إلى تقديم مفتاح/شهادة خاص بك. خلاف ذلك، سيقوم التطبيق بإنشائه.",
"samlCertificateHelpText": "يمكنك تحديد شهادتك الخاصة أو السماح للتطبيق بإنشائها.",
"samlAuthnRequestSignedHelpText": "عند التمكين، يتم توقيع طلب المصادقة SAML بالمفتاح الخاص أدناه. يتم إرسال الشهادة العامة المقابلة إلى موفر الهوية حتى يتمكن من التحقق من التوقيع.",
🤖 Prompt for AI Agents
In frontend/messages/ar.json around lines 945 to 947, the Arabic string "كتابة
فقط" is incorrect (means "write-only") while the English intends "read-only /
write-protected"; update that value to "للقراءة فقط" (or an equivalent phrase
like "للقراءة فقط — محمي من الكتابة") so the message correctly conveys
read-only/write-protected intent, preserving the rest of the sentence and
punctuation.

Comment on lines +1671 to +1675
"privateKey": "Κλειδί ιδιωτικό",
"generateDots": "Δημιουργία...",
"samlKeysGenerated": "Τα κλειδιά SAML δημιουργήθηκαν επιτυχώς",
"samlPrivateKeyHelpText": "Write-only: χρησιμοποιήστε αυτό το πεδίο μόνο αν χρειάζεται να παρέχετε δικό σας κλειδί ιδιωτικό/πιστοποιητικό. Διαφορετικά, η εφαρμογή θα το δημιουργήσει αυτόματα.",
"samlCertificateHelpText": "Μπορείτε να καθορίσετε δικό σας πιστοποιητικό ή να αφήσετε την εφαρμογή να το δημιουργήσει αυτόματα.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Greek phrasing for private key strings

Η τρέχουσα μετάφραση αντιστρέφει το ουσιαστικό/επίθετο και αφήνει το “Write-only” στα αγγλικά, κάτι που φαίνεται πρόχειρο στο UI. Παρακαλώ προσαρμόστε την ορολογία ώστε να είναι φυσική στα ελληνικά.

-	"privateKey": "Κλειδί ιδιωτικό",
+	"privateKey": "Ιδιωτικό κλειδί",
@@
-	"samlPrivateKeyHelpText": "Write-only: χρησιμοποιήστε αυτό το πεδίο μόνο αν χρειάζεται να παρέχετε δικό σας κλειδί ιδιωτικό/πιστοποιητικό. Διαφορετικά, η εφαρμογή θα το δημιουργήσει αυτόματα.",
+	"samlPrivateKeyHelpText": "Μόνο για εγγραφή (write-only): χρησιμοποιήστε αυτό το πεδίο μόνο αν χρειάζεται να παρέχετε δικό σας ιδιωτικό κλειδί/πιστοποιητικό. Διαφορετικά, η εφαρμογή θα το δημιουργήσει αυτόματα.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"privateKey": "Κλειδί ιδιωτικό",
"generateDots": "Δημιουργία...",
"samlKeysGenerated": "Τα κλειδιά SAML δημιουργήθηκαν επιτυχώς",
"samlPrivateKeyHelpText": "Write-only: χρησιμοποιήστε αυτό το πεδίο μόνο αν χρειάζεται να παρέχετε δικό σας κλειδί ιδιωτικό/πιστοποιητικό. Διαφορετικά, η εφαρμογή θα το δημιουργήσει αυτόματα.",
"samlCertificateHelpText": "Μπορείτε να καθορίσετε δικό σας πιστοποιητικό ή να αφήσετε την εφαρμογή να το δημιουργήσει αυτόματα.",
"privateKey": "Ιδιωτικό κλειδί",
"generateDots": "Δημιουργία...",
"samlKeysGenerated": "Τα κλειδιά SAML δημιουργήθηκαν επιτυχώς",
"samlPrivateKeyHelpText": "Μόνο για εγγραφή (write-only): χρησιμοποιήστε αυτό το πεδίο μόνο αν χρειάζεται να παρέχετε δικό σας ιδιωτικό κλειδί/πιστοποιητικό. Διαφορετικά, η εφαρμογή θα το δημιουργήσει αυτόματα.",
"samlCertificateHelpText": "Μπορείτε να καθορίσετε δικό σας πιστοποιητικό ή να αφήσετε την εφαρμογή να το δημιουργήσει αυτόματα.",
🤖 Prompt for AI Agents
In frontend/messages/el.json around lines 1671 to 1675, the Greek phrasing flips
noun/adjective order and leaves "Write-only" in English; update the strings to
natural Greek by placing adjectives after nouns and translating "Write-only"
(e.g., "Μόνο εγγραφή" or better "Μόνο για εγγραφή/εγγραφή μόνο") and rephrase
the help texts to sound fluent — for example change "Κλειδί ιδιωτικό" to
"Ιδιωτικό κλειδί" and rewrite "Write-only: χρησιμοποιήστε..." to a fully Greek
sentence that conveys "Μόνο για εγγραφή: χρησιμοποιήστε αυτό το πεδίο μόνο αν
χρειάζεται..." while keeping the samlCertificateHelpText similarly natural
(e.g., "Μπορείτε να παρέχετε δικό σας πιστοποιητικό ή να αφήσετε την εφαρμογή να
το δημιουργήσει αυτόματα.").

Comment on lines +982 to +983
"samlPrivateKeyHelpText": "Sólo escritura: utilice este campo solo si necesita proporcionar su propia clave/certificado privado. De lo contrario, la aplicación lo generará.",
"samlCertificateHelpText": "Puede especificar su propio certificado o dejar que la aplicación lo genere.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Correct the “read-only” wording in Spanish.

The phrase “Sólo escritura” communicates the opposite of “write-protected/read-only” from the source text. To avoid confusing users, switch it to “Sólo lectura” (or similar) in this sentence.

-"samlPrivateKeyHelpText": "Sólo escritura: utilice este campo solo si necesita proporcionar su propia clave/certificado privado. De lo contrario, la aplicación lo generará.",
+"samlPrivateKeyHelpText": "Sólo lectura: utilice este campo solo si necesita proporcionar su propia clave/certificado privado. De lo contrario, la aplicación lo generará.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"samlPrivateKeyHelpText": "Sólo escritura: utilice este campo solo si necesita proporcionar su propia clave/certificado privado. De lo contrario, la aplicación lo generará.",
"samlCertificateHelpText": "Puede especificar su propio certificado o dejar que la aplicación lo genere.",
"samlPrivateKeyHelpText": "Sólo lectura: utilice este campo solo si necesita proporcionar su propia clave/certificado privado. De lo contrario, la aplicación lo generará.",
"samlCertificateHelpText": "Puede especificar su propio certificado o dejar que la aplicación lo genere.",
🤖 Prompt for AI Agents
In frontend/messages/es.json around lines 982 to 983, the Spanish string for
samlPrivateKeyHelpText uses "Sólo escritura" which incorrectly conveys
"write-only"; replace it with "Sólo lectura" (or equivalent like "Solo lectura"
if following project accent rules) so the sentence reads that the field is
read-only/for display only and matches the original meaning; update the JSON
value accordingly and ensure punctuation/spacing remains consistent with
neighboring entries.

"action": "क्रिया"
"action": "कार्रवाई",
"privateKey": "निजी कुंजी",
"generateDots": "उत्पन्न...",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Complete the imperative phrase for “Generate…”

“उत्पन्न...” truncates the imperative and reads awkwardly in Hindi. Adding “करें” keeps it consistent with other buttons (e.g., “डाउनलोड करें”).

-	"generateDots": "उत्पन्न...",
+	"generateDots": "उत्पन्न करें...",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"generateDots": "उत्पन्न...",
"generateDots": "उत्पन्न करें...",
🤖 Prompt for AI Agents
In frontend/messages/hi.json around line 944, the translation string
"generateDots": "उत्पन्न..." uses an incomplete imperative; replace it with a
complete imperative phrase like "उत्पन्न करें" to match other button labels
(e.g., "डाउनलोड करें") and maintain consistent tone across the UI.

"action": "कार्रवाई",
"privateKey": "निजी कुंजी",
"generateDots": "उत्पन्न...",
"samlKeysGenerated": "सामल कुंजियाँ सफलतापूर्वक उत्पन्न की गईं",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep the “SAML” acronym unchanged

Line 945 spells “SAML” as “सामल”, which diverges from the established acronym usage elsewhere in this file (e.g., “SAML IdP कॉन्फ़िगरेशन”). Please retain the uppercase Latin acronym for consistency and to avoid confusing readers.

-	"samlKeysGenerated": "सामल कुंजियाँ सफलतापूर्वक उत्पन्न की गईं",
+	"samlKeysGenerated": "SAML कुंजियाँ सफलतापूर्वक उत्पन्न की गईं",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"samlKeysGenerated": "सामल कुंजियाँ सफलतापूर्वक उत्पन्न की गईं",
"samlKeysGenerated": "SAML कुंजियाँ सफलतापूर्वक उत्पन्न की गईं",
🤖 Prompt for AI Agents
In frontend/messages/hi.json around line 945, the string uses the Devanagari
transliteration "सामल" for the SAML acronym; replace that token with the
uppercase Latin acronym "SAML" so the value becomes "SAML कुंजियाँ सफलतापूर्वक
उत्पन्न की गईं" to match other entries (e.g., "SAML IdP कॉन्फ़िगरेशन") and keep
acronym usage consistent.

Comment on lines +1352 to +1355
"samlPrivateKeyHelpText": "Scrittura sola: usa questo campo solo se devi fornire la tua chiave/certificato privata. Altrimenti, l'applicazione lo genererà.",
"samlCertificateHelpText": "Puoi specificare il tuo certificato o lasciare che l'applicazione lo generi.",
"samlAuthnRequestSignedHelpText": "Quando abilitato, la richiesta di autenticazione SAML viene firmata con la chiave privata qui sotto. Il certificato pubblico corrispondente viene inviato al Provider di Identità in modo che possa verificare la firma.",
"downloadCertificate": "Scarica certificato"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Italian help text grammar for clarity

The current sentence starts with “Scrittura sola” and mixes genders/numbers in “chiave/certificato privata.” Please rephrase to a natural Italian wording such as “Solo scrittura: usa questo campo solo se devi fornire la tua chiave privata o il tuo certificato. In caso contrario, l’applicazione li genererà.”

🤖 Prompt for AI Agents
In frontend/messages/it.json around lines 1352-1355, the Italian help text for
samlPrivateKeyHelpText is ungrammatical and mixes genders/numbers; replace its
value with a natural, corrected sentence like: Solo scrittura: usa questo campo
solo se devi fornire la tua chiave privata o il tuo certificato. In caso
contrario, l’applicazione li genererà. Ensure the JSON string uses proper
punctuation and apostrophe (l’applicazione) and matches the file’s
quoting/escaping conventions.

Comment on lines +972 to +976
"generateDots": "Generare...",
"samlKeysGenerated": "Cheile SAML au fost generate cu succes",
"samlPrivateKeyHelpText": "Doar scriere: utilizați acest câmp numai dacă aveți nevoie să furnizați propria cheie/certificat privat. În caz contrar, aplicația va genera cheia.",
"samlCertificateHelpText": "Puteți specifica propriul certificat sau lăsați aplicația să-l genereze.",
"samlAuthnRequestSignedHelpText": "Când este activat, cererea de autentificare SAML este semnată cu cheia privată de mai jos. Certificatul public corespunzător este trimis furnizorului de identitate pentru a putea verifica semnătura.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix awkward Romanian phrasing for “write-only”.

The string "Doar scriere" reads as a literal translation and is confusing. A natural phrasing would be "Numai pentru scriere" (or "Doar pentru scriere"), keeping the intended meaning of “write-only”.

-	"samlPrivateKeyHelpText": "Doar scriere: utilizați acest câmp numai dacă aveți nevoie să furnizați propria cheie/certificat privat. În caz contrar, aplicația va genera cheia.",
+	"samlPrivateKeyHelpText": "Numai pentru scriere: utilizați acest câmp numai dacă aveți nevoie să furnizați propria cheie/certificat privat. În caz contrar, aplicația va genera cheia.",
🤖 Prompt for AI Agents
In frontend/messages/ro.json around lines 972 to 976, the phrase "Doar scriere"
is an awkward literal translation for "write-only"; change it to a natural
Romanian phrasing such as "Numai pentru scriere" (or "Doar pentru scriere") in
the "samlPrivateKeyHelpText" value so the meaning "write-only" is clear and
reads naturally.

"privateKey": "Privat nyckel",
"generateDots": "Genererar...",
"samlKeysGenerated": "SAML-nycklar genererades framgångsrikt",
"samlPrivateKeyHelpText": "Skrivskyddad: använd endast detta fält om du behöver ange din egen privata nyckel/certifikat. Annars kommer applikationen att generera det.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Swedish grammatical gender in help text.

"For field" (fält) is neuter, so the prefix should be Skrivskyddat, not Skrivskyddad. Please adjust to avoid a visible grammar glitch in the UI.

-	"samlPrivateKeyHelpText": "Skrivskyddad: använd endast detta fält om du behöver ange din egen privata nyckel/certifikat. Annars kommer applikationen att generera det.",
+	"samlPrivateKeyHelpText": "Skrivskyddat: använd endast detta fält om du behöver ange din egen privata nyckel/certifikat. Annars kommer applikationen att generera det.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"samlPrivateKeyHelpText": "Skrivskyddad: använd endast detta fält om du behöver ange din egen privata nyckel/certifikat. Annars kommer applikationen att generera det.",
"samlPrivateKeyHelpText": "Skrivskyddat: använd endast detta fält om du behöver ange din egen privata nyckel/certifikat. Annars kommer applikationen att generera det.",
🤖 Prompt for AI Agents
In frontend/messages/sv.json around line 968 the Swedish help text uses the
feminine adjective "Skrivskyddad" but the noun "fält" is neuter; change the
adjective to the neuter form "Skrivskyddat" in the value for
"samlPrivateKeyHelpText" so the sentence reads correctly.

Comment on lines +1709 to +1712
"samlKeysGenerated": "Saml anahtarları başarıyla oluşturuldu",
"samlPrivateKeyHelpText": "Yalnızca yazma: özel anahtar/belgenizi sağlamanız gerekiyorsa bu alanı kullanın. Aksi takdirde uygulama onu oluşturacaktır.",
"samlCertificateHelpText": "Kendi sertifikanızı belirleyebilir veya uygulamanın oluşturmasını sağlayabilirsiniz.",
"samlAuthnRequestSignedHelpText": "Etkinleştirildiğinde, SAML kimlik doğrulama isteği aşağıdaki özel anahtar ile imzalanır. İmzayı doğrulayabilmesi için ilgili genel sertifika Kimlik Sağlayıcıya gönderilir.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep SAML acronym uppercase

“Saml” should stay uppercase to match the official acronym and the rest of the locales.

-	"samlKeysGenerated": "Saml anahtarları başarıyla oluşturuldu",
+	"samlKeysGenerated": "SAML anahtarları başarıyla oluşturuldu",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"samlKeysGenerated": "Saml anahtarları başarıyla oluşturuldu",
"samlPrivateKeyHelpText": "Yalnızca yazma: özel anahtar/belgenizi sağlamanız gerekiyorsa bu alanı kullanın. Aksi takdirde uygulama onu oluşturacaktır.",
"samlCertificateHelpText": "Kendi sertifikanızı belirleyebilir veya uygulamanın oluşturmasını sağlayabilirsiniz.",
"samlAuthnRequestSignedHelpText": "Etkinleştirildiğinde, SAML kimlik doğrulama isteği aşağıdaki özel anahtar ile imzalanır. İmzayı doğrulayabilmesi için ilgili genel sertifika Kimlik Sağlayıcıya gönderilir.",
"samlKeysGenerated": "SAML anahtarları başarıyla oluşturuldu",
"samlPrivateKeyHelpText": "Yalnızca yazma: özel anahtar/belgenizi sağlamanız gerekiyorsa bu alanı kullanın. Aksi takdirde uygulama onu oluşturacaktır.",
"samlCertificateHelpText": "Kendi sertifikanızı belirleyebilir veya uygulamanın oluşturmasını sağlayabilirsiniz.",
"samlAuthnRequestSignedHelpText": "Etkinleştirildiğinde, SAML kimlik doğrulama isteği aşağıdaki özel anahtar ile imzalanır. İmzayı doğrulayabilmesi için ilgili genel sertifika Kimlik Sağlayıcıya gönderilir.",
🤖 Prompt for AI Agents
In frontend/messages/tr.json around lines 1709 to 1712, the SAML acronym in the
translation values is currently "Saml"; update each occurrence to uppercase
"SAML" (e.g., "Saml anahtarları başarıyla oluşturuldu" -> "SAML anahtarları
başarıyla oluşturuldu", and similarly for the other three help text values) so
the acronym matches the official uppercase usage and other locales.

Comment on lines +942 to +948
"privateKey": "کلی پریویٹ",
"generateDots": "تخلیق کریں...",
"samlKeysGenerated": "Saml کلیاں کامیابی کے ساتھ تیار کی گئیں",
"samlPrivateKeyHelpText": "صرف لکھنے کے لیے: صرف اس فیلڈ کو استعمال کریں اگر آپ اپنی ذاتی کلی/سرٹیفکیٹ فراہم کرنے کی ضرورت ہے۔ ورنہ، ایپلی کیشن اسے تیار کرے گا۔",
"samlCertificateHelpText": "آپ اپنی اپنی سرٹیفکیٹ فراہم کر سکتے ہیں یا ایپلی کیشن کو اسے تیار کرنے دیں۔",
"samlAuthnRequestSignedHelpText": "جب فعال ہو، تو SAML توثیق کی درخواست نیچے دی گئی پریویٹ کلی کے ساتھ سائن کی جاتی ہے۔ متعلقہ پبلک سرٹیفکیٹ کو شناخت فراہم کنندہ کو بھیجا جاتا ہے تاکہ وہ دستخط کی تصدیق کر سکے۔",
"downloadCertificate": "سرٹیفکیٹ ڈاؤن لوڈ کریں"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix mistranslated SAML key strings

Several of the newly added Urdu strings use “کلی/کلیاں,” which means flower buds, instead of the intended “کلید/کلیدیں” (keys). This will read nonsensically to native speakers. For example, “کلی پریویٹ” and “Saml کلیاں” should be “نجی کلید” and “SAML کلیدیں.” Please update the affected entries accordingly.

-	"privateKey": "کلی پریویٹ",
+	"privateKey": "نجی کلید",
-	"samlKeysGenerated": "Saml کلیاں کامیابی کے ساتھ تیار کی گئیں",
+	"samlKeysGenerated": "SAML کلیدیں کامیابی کے ساتھ تیار کی گئیں",
-	"samlPrivateKeyHelpText": "صرف لکھنے کے لیے: صرف اس فیلڈ کو استعمال کریں اگر آپ اپنی ذاتی کلی/سرٹیفکیٹ فراہم کرنے کی ضرورت ہے۔ ورنہ، ایپلی کیشن اسے تیار کرے گا۔",
+	"samlPrivateKeyHelpText": "صرف لکھنے کے لیے: صرف اس فیلڈ کو استعمال کریں اگر آپ اپنی ذاتی کلید/سرٹیفکیٹ فراہم کرنا چاہتے ہیں۔ ورنہ، ایپلی کیشن اسے تیار کرے گا۔",
-	"samlAuthnRequestSignedHelpText": "جب فعال ہو، تو SAML توثیق کی درخواست نیچے دی گئی پریویٹ کلی کے ساتھ سائن کی جاتی ہے۔ متعلقہ پبلک سرٹیفکیٹ کو شناخت فراہم کنندہ کو بھیجا جاتا ہے تاکہ وہ دستخط کی تصدیق کر سکے۔",
+	"samlAuthnRequestSignedHelpText": "جب فعال ہو، تو SAML توثیق کی درخواست نیچے دی گئی نجی کلید کے ساتھ سائن کی جاتی ہے۔ متعلقہ عوامی سرٹیفکیٹ کو شناخت فراہم کنندہ کو بھیجا جاتا ہے تاکہ وہ دستخط کی تصدیق کر سکے۔"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"privateKey": "کلی پریویٹ",
"generateDots": "تخلیق کریں...",
"samlKeysGenerated": "Saml کلیاں کامیابی کے ساتھ تیار کی گئیں",
"samlPrivateKeyHelpText": "صرف لکھنے کے لیے: صرف اس فیلڈ کو استعمال کریں اگر آپ اپنی ذاتی کلی/سرٹیفکیٹ فراہم کرنے کی ضرورت ہے۔ ورنہ، ایپلی کیشن اسے تیار کرے گا۔",
"samlCertificateHelpText": "آپ اپنی اپنی سرٹیفکیٹ فراہم کر سکتے ہیں یا ایپلی کیشن کو اسے تیار کرنے دیں۔",
"samlAuthnRequestSignedHelpText": "جب فعال ہو، تو SAML توثیق کی درخواست نیچے دی گئی پریویٹ کلی کے ساتھ سائن کی جاتی ہے۔ متعلقہ پبلک سرٹیفکیٹ کو شناخت فراہم کنندہ کو بھیجا جاتا ہے تاکہ وہ دستخط کی تصدیق کر سکے۔",
"downloadCertificate": "سرٹیفکیٹ ڈاؤن لوڈ کریں"
"privateKey": "نجی کلید",
"generateDots": "تخلیق کریں...",
"samlKeysGenerated": "SAML کلیدیں کامیابی کے ساتھ تیار کی گئیں",
"samlPrivateKeyHelpText": "صرف لکھنے کے لیے: صرف اس فیلڈ کو استعمال کریں اگر آپ اپنی ذاتی کلید/سرٹیفکیٹ فراہم کرنا چاہتے ہیں۔ ورنہ، ایپلی کیشن اسے تیار کرے گا۔",
"samlCertificateHelpText": "آپ اپنی اپنی سرٹیفکیٹ فراہم کر سکتے ہیں یا ایپلی کیشن کو اسے تیار کرنے دیں۔",
"samlAuthnRequestSignedHelpText": "جب فعال ہو، تو SAML توثیق کی درخواست نیچے دی گئی نجی کلید کے ساتھ سائن کی جاتی ہے۔ متعلقہ عوامی سرٹیفکیٹ کو شناخت فراہم کنندہ کو بھیجا جاتا ہے تاکہ وہ دستخط کی تصدیق کر سکے۔",
"downloadCertificate": "سرٹیفکیٹ ڈاؤن لوڈ کریں"
🤖 Prompt for AI Agents
In frontend/messages/ur.json around lines 942-948 several Urdu translations use
"کلی/کلیاں" (flower buds) and "پریویٹ" instead of the correct crypto terms;
replace these occurrences: change "کلی پریویٹ" to "نجی کلید", "Saml کلیاں
کامیابی کے ساتھ تیار کی گئیں" to "SAML کلیدیں کامیابی کے ساتھ تیار کی گئیں",
change "ذاتی کلی/سرٹیفکیٹ" inside samlPrivateKeyHelpText to "ذاتی
کلید/سرٹیفکیٹ", and change "پریویٹ کلی" in samlAuthnRequestSignedHelpText to
"نجی کلید"; ensure "Saml" is normalized to "SAML" where appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant