{"record":{"id":"64a7d0b7536b063b","repo":"apereo/cas","slug":"dn-format-cannot-be-empty-blank-for-authentication","errorCode":null,"errorMessage":"Dn format cannot be empty/blank for authentication","messagePattern":"Dn format cannot be empty/blank for authentication","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/util/LdapUtils.java","lineNumber":805,"sourceCode":"        if (StringUtils.isBlank(properties.getSearchFilter())) {\n            throw new IllegalArgumentException(\"User filter cannot be empty/blank for authenticated/anonymous authentication\");\n        }\n        val connectionFactory = newLdaptiveConnectionFactory(properties);\n        val resolver = buildAggregateDnResolver(properties, connectionFactory);\n\n        val auth = StringUtils.isBlank(properties.getPrincipalAttributePassword())\n            ? new Authenticator(resolver, getBindAuthenticationHandler(connectionFactory))\n            : new Authenticator(resolver, getCompareAuthenticationHandler(properties, connectionFactory));\n\n        if (properties.isEnhanceWithEntryResolver()) {\n            auth.setEntryResolver(newLdaptiveSearchEntryResolver(properties, connectionFactory));\n        }\n        return auth;\n    }\n\n    private static Authenticator getDnFormatAuthenticator(final AbstractLdapAuthenticationProperties properties) {\n        if (StringUtils.isBlank(properties.getDnFormat())) {\n            throw new IllegalArgumentException(\"Dn format cannot be empty/blank for authentication\");\n        }\n        return getAuthenticatorViaDnFormat(properties, newLdaptiveConnectionFactory(properties));\n    }\n\n    private static Authenticator getAuthenticatorViaDnFormat(final AbstractLdapAuthenticationProperties properties,\n                                                             final ConnectionFactory factory) {\n        val resolver = new FormatDnResolver(properties.getDnFormat());\n        val authenticator = new Authenticator(resolver, getBindAuthenticationHandler(factory));\n\n        if (properties.isEnhanceWithEntryResolver()) {\n            authenticator.setEntryResolver(newLdaptiveSearchEntryResolver(properties, factory));\n        }\n        return authenticator;\n    }\n\n    private static AuthenticationHandler getBindAuthenticationHandler(final ConnectionFactory factory) {\n        return new SimpleBindAuthenticationHandler(factory);\n    }","sourceCodeStart":787,"sourceCodeEnd":823,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-ldap-core/src/main/java/org/apereo/cas/util/LdapUtils.java#L787-L823","documentation":"CAS's LdapUtils builds an LDAP authenticator from `cas.authn.ldap[*].dn-format`; the DN format template is what ldaptive uses to turn a submitted username into an entry DN. When `getDnFormatAuthenticator` finds the configured dnFormat blank, no DN can ever be formed, so it fails fast with this IllegalArgumentException during authenticator construction at startup/configuration refresh.","triggerScenarios":"Configuring an LDAP authentication handler with direct bind (search-less) mode but leaving `cas.authn.ldap[...].dn-format` empty, whitespace-only, or undefined; the error is raised when newLdaptiveAuthenticator calls getDnFormatAuthenticator.","commonSituations":"Copy-pasting LDAP config samples without setting dn-format; switching from search-bind mode (where dn-format is unused) to direct bind and forgetting to add it; YAML/properties typos leaving the key empty; templated config where a placeholder like ${dnFormat} resolves to empty.","solutions":["Set a DN format template in properties, e.g. cas.authn.ldap[0].dn-format=uid=%s,ou=people,dc=example,dc=org","Verify the property actually resolves (check property source precedence, profile-specific overrides) so it is not blank at runtime","If your directory cannot use a single DN template, switch to search-bind mode by setting base-dn plus search-filter instead of dn-format"],"exampleFix":"// before\ncas.authn.ldap[0].type=DIRECT\ncas.authn.ldap[0].dn-format=\n\n// after\ncas.authn.ldap[0].type=DIRECT\ncas.authn.ldap[0].dn-format=uid=%s,ou=people,dc=example,dc=org","handlingStrategy":"validation","validationCode":"if (StringUtils.isBlank(casProperties.getAuthn().getLdap().get(0).getDnFormat())) {\n    throw new IllegalStateException(\"cas.authn.ldap[0].dn-format must be set for direct bind\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    authenticator = LdapUtils.newLdaptiveAuthenticator(props);\n} catch (IllegalArgumentException e) {\n    logger.error(\"LDAP dn-format misconfigured: {}\", e.getMessage());\n    throw e; // fail fast at startup\n}","preventionTips":["Always set dn-format when using DIRECT bind type; use base-dn + search-filter when using SEARCH bind","Add a startup smoke test that constructs all configured authenticators","Keep LDAP settings in one reviewed profile-specific file to avoid blank overrides"],"tags":["ldap","configuration","cas"],"backgroundTag":"missing-required-config-field","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}