{"record":{"id":"e5e3b405cd7e9618","repo":"spring-projects/spring-security","slug":"no-matching-pattern-was-found-in-subject-dn-0-e5e3b4","errorCode":null,"errorMessage":"No matching pattern was found in subject DN: {0}","messagePattern":"No matching pattern was found in subject DN: (.+?)","errorType":"exception","errorClass":"BadCredentialsException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java","lineNumber":94,"sourceCode":"\t\ttry {\n\t\t\t// read most-specific first, see gh-19254\n\t\t\tList<Rdn> rdns = new ArrayList<>(new LdapName(subjectDn).getRdns());\n\t\t\tCollections.reverse(rdns);\n\t\t\treturn rdns;\n\t\t}\n\t\tcatch (InvalidNameException ex) {\n\t\t\tthrow new BadCredentialsException(\"Failed to parse client certificate\", ex);\n\t\t}\n\t}\n\n\tprivate String getSubject(String subjectDn) {\n\t\tfor (Rdn rdn : getDns(subjectDn)) {\n\t\t\tString type = rdn.getType();\n\t\t\tif (this.subjectDnType.equals(type)) {\n\t\t\t\treturn String.valueOf(rdn.getValue());\n\t\t\t}\n\t\t}\n\t\tthrow new BadCredentialsException(this.messages.getMessage(\"SubjectX500PrincipalExtractor.noMatching\",\n\t\t\t\tnew Object[] { subjectDn }, \"No matching pattern was found in subject DN: {0}\"));\n\t}\n\n\t@Override\n\tpublic void setMessageSource(MessageSource messageSource) {\n\t\tAssert.notNull(messageSource, \"messageSource cannot be null\");\n\t\tthis.messages = new MessageSourceAccessor(messageSource);\n\t}\n\n\t/**\n\t * Sets if the principal name should be extracted from the emailAddress or CN\n\t * attribute (default).\n\t *\n\t * By default, the format {@link X500Principal#RFC2253} is passed to\n\t * {@link X500Principal#getName(String)} and the principal is extracted from the CN\n\t * attribute as defined in\n\t * <a href=\"https://datatracker.ietf.org/doc/html/rfc2253#section-2.3\">Converting\n\t * AttributeTypeAndValue of RFC2253</a>.","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectX500PrincipalExtractor.java#L76-L112","documentation":"SubjectX500PrincipalExtractor looks for the RDN whose type equals the configured subjectDnType (default 'CN') in the subject DN and returns its value. If no RDN of that type exists it throws BadCredentialsException with 'No matching pattern was found in subject DN: {0}'.","triggerScenarios":"Calling getSubject (via principalName) when the DN contains no RDN whose type matches the configured type — e.g. the extractor expects 'CN' but the certificate only has emailAddress/UID/O attributes, or subjectDnType was set with wrong case ('cn' vs 'CN') so equals fails.","commonSituations":"Certificates from a CA that uses UID or emailAddress instead of CN; misconfigured extractor.setSubjectDnType(\"cn\") while the DN uses 'CN' (case-sensitive comparison); certificates with an empty or minimal subject.","solutions":["Run 'openssl x509 -in cert.pem -noout -subject' to see which RDN types your certificates actually contain.","Call extractor.setSubjectDnType() with the exact type string present in the DN (case-sensitive, e.g. \"CN\", \"UID\", \"emailAddress\").","If the identifier lives in an RDN not expressible as a simple type match, use SubjectDnX509PrincipalExtractor with a custom regex instead.","Ensure the certificate template/CA issues certs that include the expected RDN."],"exampleFix":"// before\nSubjectX500PrincipalExtractor extractor = new SubjectX500PrincipalExtractor(); // expects CN\n// after\nSubjectX500PrincipalExtractor extractor = new SubjectX500PrincipalExtractor();\nextractor.setSubjectDnType(\"UID\"); // match the RDN type actually present in the certificate DN","handlingStrategy":"validation","validationCode":"String dn = cert.getSubjectX500Principal().getName(X500Principal.RFC2253);\nboolean hasType = new LdapName(dn).getRdns().stream()\n    .anyMatch(rdn -> rdn.getType().equalsIgnoreCase(\"CN\"));\nif (!hasType) throw new IllegalArgumentException(\"Certificate DN lacks expected RDN type\");","typeGuard":"boolean dnContainsRdnType(String dn, String type) {\n    try {\n        return new LdapName(dn).getRdns().stream()\n            .anyMatch(r -> r.getType().equals(type));\n    } catch (InvalidNameException e) { return false; }\n}","tryCatchPattern":"try {\n    return extractor.extractPrincipal(cert);\n} catch (BadCredentialsException e) {\n    log.warn(\"DN missing RDN type '{}': {}\", expectedType, cert.getSubjectX500Principal());\n    return null;\n}","preventionTips":["Match subjectDnType to a type actually present in your certs (case-sensitive: \"CN\", \"UID\")","Check certs with openssl x509 -noout -subject before configuring","Ensure the CA template always includes the identifier RDN","Consider case-insensitive pre-validation since the extractor compares with equals"],"tags":["x509","dn","authentication","spring-security"],"backgroundTag":"resource-not-found","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}