{"record":{"id":"969dc4692fff506f","repo":"apache/pulsar","slug":"cannot-create-sasl-client-with-empty-jaas-subject","errorCode":null,"errorMessage":"Cannot create SASL client with empty JAAS subject principal","messagePattern":"Cannot create SASL client with empty JAAS subject principal","errorType":"exception","errorClass":"SaslException","httpStatus":null,"severity":"error","filePath":"pulsar-client-auth-sasl/src/main/java/org/apache/pulsar/client/impl/auth/PulsarSaslClient.java","lineNumber":60,"sourceCode":" * This is added for support Kerberos authentication.\n */\n@CustomLog\npublic class PulsarSaslClient {\n    private final SaslClient saslClient;\n    private final Subject clientSubject;\n\n    public PulsarSaslClient(String serverHostname, String serverType, Subject subject) throws SaslException {\n        checkArgument(subject != null, \"Cannot create SASL client with NULL JAAS subject\");\n        checkArgument(!Strings.isNullOrEmpty(serverHostname), \"Cannot create SASL client with NUll server name\");\n        if (!serverType.equals(SaslConstants.SASL_BROKER_PROTOCOL) && !serverType\n                                                                           .equals(SaslConstants.SASL_PROXY_PROTOCOL)) {\n            log.warn().attr(\"serverType\", serverType).log(\"The server type is not recommended\");\n        }\n\n        String serverPrincipal = serverType.toLowerCase() + \"/\" + serverHostname;\n        this.clientSubject = subject;\n        if (clientSubject.getPrincipals().isEmpty()) {\n            throw new SaslException(\"Cannot create SASL client with empty JAAS subject principal\");\n        }\n        // GSSAPI/Kerberos\n        final Object[] principals = clientSubject.getPrincipals().toArray();\n        final Principal clientPrincipal = (Principal) principals[0];\n\n        final KerberosName clientKerberosName = new KerberosName(clientPrincipal.getName());\n        KerberosName serviceKerberosName = new KerberosName(serverPrincipal + \"@\" + clientKerberosName.getRealm());\n        final String serviceName = serviceKerberosName.getServiceName();\n        final String serviceHostname = serviceKerberosName.getHostName();\n        final String clientPrincipalName = clientKerberosName.toString();\n        log.info().attr(\"serverPrincipal\", serverPrincipal)\n                .log(\"Using JAAS/SASL/GSSAPI auth to connect to server\");\n\n        try {\n            this.saslClient = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SaslClient>() {\n                @Override\n                public SaslClient run() throws SaslException {\n                    String[] mechs = {\"GSSAPI\"};","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-auth-sasl/src/main/java/org/apache/pulsar/client/impl/auth/PulsarSaslClient.java#L42-L78","documentation":"PulsarSaslClient's constructor validates that the JAAS Subject used as the client identity has at least one Principal; an empty principal set means the subject carries no authenticated identity (no Kerberos user), so the GSSAPI mechanism cannot be built. It throws SaslException with this message.","triggerScenarios":"Constructing PulsarSaslClient with a Subject produced by a failed or no-op JAAS login — e.g. the LoginContext logged in a subject with no principals because the Krb5LoginModule was skipped (useKeyTab=false with no ticket, debug misconfig) or the login silently produced an empty subject.","commonSituations":"Kerberos keytab path wrong or unreadable so login falls through without a principal; JAAS section misconfigured (wrong principal/debug flags) causing login to succeed with zero principals; passing new Subject() or a subject created without doAsPrivileged login; expired TGT combined with a module configured not to fail.","solutions":["Verify the JAAS login actually produces a principal: after LoginContext.login(), assert !subject.getPrincipals().isEmpty() before constructing PulsarSaslClient.","Fix the JAAS config file: ensure the section (default PulsarClient) uses com.sun.security.auth.module.Krb5LoginModule with required/ sufficient flag and a valid keyTab/principal.","Confirm the keytab exists and is readable, and that kinit/klist shows valid credentials.","Check that login failure isn't being swallowed — JAAS modules with optional flag won't throw but yield an empty subject."],"exampleFix":"// before\nSubject subject = new Subject(); // empty, no login performed\nPulsarSaslClient client = new PulsarSaslClient(host, \"broker\", subject); // SaslException\n// after\nLoginContext lc = new LoginContext(\"PulsarClient\");\nlc.login();\nSubject subject = lc.getSubject();\nif (subject.getPrincipals().isEmpty()) { throw new IllegalStateException(\"JAAS login produced no principal\"); }\nPulsarSaslClient client = new PulsarSaslClient(host, \"broker\", subject);","handlingStrategy":"validation","validationCode":"// Java: verify the JAAS subject has principals before constructing PulsarSaslClient\nstatic void validateSubject(Subject subject) {\n    if (subject == null || subject.getPrincipals().isEmpty()) {\n        throw new IllegalStateException(\"JAAS subject has no principals; login failed or was skipped\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    PulsarSaslClient client = new PulsarSaslClient(host, serverType, subject);\n} catch (SaslException e) {\n    if (e.getMessage().contains(\"empty JAAS subject principal\")) {\n        throw new IllegalStateException(\"Kerberos login produced no principal — check JAAS config and kinit\", e);\n    }\n    throw e;\n}","preventionTips":["After LoginContext.login(), assert !subject.getPrincipals().isEmpty().","Use required/sufficient (not optional) flags for Krb5LoginModule so failed login throws instead of yielding an empty subject.","Verify keytab path/permissions and run klist before starting the client.","Never pass a manually constructed new Subject() without a completed login."],"tags":["kerberos","sasl","jaas","authentication"],"backgroundTag":"kerberos-login-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}