{"record":{"id":"201cfd329c26a470","repo":"SonarSource/sonarqube","slug":"invalid-certificate","errorCode":null,"errorMessage":"Invalid certificate","messagePattern":"Invalid certificate","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlCertificateConverter.java","lineNumber":42,"sourceCode":"import java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.Base64;\nimport org.sonar.api.server.ServerSide;\n\n@ServerSide\nclass SamlCertificateConverter {\n\n  public static final String SPACES = \"\\\\s+\";\n\n  X509Certificate toX509Certificate(String certificateString) {\n    String cleanedCertificateString = sanitizeCertificateString(certificateString);\n\n    byte[] decoded = Base64.getDecoder().decode(cleanedCertificateString);\n    try {\n      CertificateFactory factory = CertificateFactory.getInstance(\"X.509\");\n      return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(decoded));\n    } catch (CertificateException e) {\n      throw new IllegalStateException(\"Invalid certificate\", e);\n    }\n  }\n\n  private static String sanitizeCertificateString(String certificateString) {\n    return certificateString\n      .replace(\"-----BEGIN CERTIFICATE-----\", \"\")\n      .replace(\"-----END CERTIFICATE-----\", \"\")\n      .replaceAll(SPACES, \"\");\n  }\n}\n","sourceCodeStart":24,"sourceCodeEnd":53,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-auth-saml/src/main/java/org/sonar/auth/saml/SamlCertificateConverter.java#L24-L53","documentation":"SamlCertificateConverter.toX509Certificate() parses a Base64-encoded X.509 certificate string (PEM headers already stripped by sanitizeCertificateString) into a java.security.cert.X509Certificate. If CertificateFactory.generateCertificate() throws CertificateException, the bytes are not a valid DER-encoded X.509 certificate, so it wraps the failure in an IllegalStateException with this message. This is a fail-fast guard: the SAML plugin cannot work without a usable SP certificate.","triggerScenarios":"Calling toX509Certificate() (directly or via SonarQube SAML settings loading) with a value that is not valid Base64-then-DER X.509 data: truncated certificate, HTML-escaped PEM, missing or wrong header (e.g. '-----BEGIN CERTIFICATE-----' kept but a private key body pasted, or a PKCS#7 'BEGIN CERTIFICATE' chain), or a value containing whitespace/newlines in the wrong place.","commonSituations":"Admins pasting the IdP metadata certificate incorrectly, copying the SP private key into the certificate field, copy/paste introducing smart quotes or HTML entities, or uploading a DER binary file pasted as text.","solutions":["Verify the sonar.auth.saml.certificate value is the Base64 body of an X.509 certificate without the BEGIN/END lines, on a single logical Base64 stream","Re-export the certificate with: openssl x509 -in cert.pem -outform PEM and paste only the Base64 body","Check the field mapping — certificate field got the private key or vice versa (private key goes to sonar.auth.saml.privateKey)"],"exampleFix":"// before (invalid: full PEM with escaped newlines pasted into settings)\nString cert = \"-----BEGIN CERTIFICATE-----\\nMIID...\\n-----END CERTIFICATE-----\";\n// after (Base64 body only, headers stripped)\nString cert = \"MIIDdzCCAl+gAwIBAgIE...\";","handlingStrategy":"validation","validationCode":"String cleaned = cert.replace(\"-----BEGIN CERTIFICATE-----\", \"\").replace(\"-----END CERTIFICATE-----\", \"\").replaceAll(\"\\\\s\", \"\");\nbyte[] decoded = Base64.getDecoder().decode(cleaned);\ntry {\n  new X509CertImpl(decoded); // or CertificateFactory dry-run\n} catch (CertificateException | IOException e) {\n  throw new IllegalArgumentException(\"Not a valid X.509 certificate\");\n}","typeGuard":"static boolean looksLikeX509Pem(String s) {\n  return s != null && !s.contains(\"PRIVATE KEY\") && s.matches(\"(?s).*[A-Za-z0-9+/=]{100,}.*\");\n}","tryCatchPattern":"try {\n  X509Certificate cert = SamlCertificateConverter.toX509Certificate(cfg.certificate());\n} catch (IllegalStateException e) {\n  log.error(\"SAML certificate invalid, check sonar.auth.saml.certificate\", e);\n  throw new ConfigurationException(\"Fix the SAML certificate setting\");\n}","preventionTips":["Paste only the Base64 body of the certificate, never the BEGIN/END lines","Export as PEM (openssl x509 -outform PEM) rather than DER binary","Verify with `openssl x509 -in cert.pem -noout -subject` before configuring","Sanity-check you did not paste the private key into the certificate field"],"tags":["saml","certificate","x509","config"],"backgroundTag":"invalid-argument-format","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}