{"record":{"id":"21122aacff794b80","repo":"apache/pulsar","slug":"authentication-use-sasl-jaas-gssapi-but-server-not","errorCode":null,"errorMessage":"Authentication use SASL/JAAS/GSSAPI but server not have Principals","messagePattern":"Authentication use SASL/JAAS/GSSAPI but server not have Principals","errorType":"exception","errorClass":"SaslException","httpStatus":null,"severity":"critical","filePath":"pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/PulsarSaslServer.java","lineNumber":119,"sourceCode":"                                    saslServer = Sasl.createSaslServer(GSSAPI, servicePrincipalName, serviceHostname,\n                                        null, callbackHandler);\n                                    return saslServer;\n                                } catch (SaslException e) {\n                                    throw new RuntimeException(e);\n                                }\n                            }\n                        }\n                    );\n                } catch (PrivilegedActionException e) {\n                    throw new SaslException(\"error on GSSAPI boot\", e.getCause());\n                }\n            } catch (IndexOutOfBoundsException e) {\n                throw new SaslException(\"error on GSSAPI boot\", e);\n            }\n        } else {\n            String errorMessage = \"Authentication use SASL/JAAS/GSSAPI but server not have Principals\";\n            log.error(errorMessage);\n            throw new SaslException(errorMessage);\n        }\n    }\n\n    public boolean isComplete() {\n        return saslServer.isComplete();\n    }\n\n    /**\n     * Reports the authorization ID in effect for the client of this\n     * session.\n     * This method can only be called if isComplete() returns true.\n     * @return The authorization ID of the client.\n     * @exception IllegalStateException if this authentication session has not completed\n     */\n    public String getAuthorizationID() throws IllegalStateException {\n        return saslServer.getAuthorizationID();\n    }\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker-auth-sasl/src/main/java/org/apache/pulsar/broker/authentication/PulsarSaslServer.java#L101-L137","documentation":"Thrown as a javax.security.sasl.SaslException when the broker's SASL/GSSAPI (Kerberos) server is constructed but the JAAS Subject supplied to PulsarSaslServer contains no Principals. The GSSAPI mechanism requires the server to hold a Kerberos service principal (e.g. broker/myhost@REALM) loaded via a JAAS login (Krb5LoginModule); without it, SASL cannot be bootstrapped, so createSaslServer fails fast.","triggerScenarios":"Constructing PulsarSaslServer (new PulsarSaslServer(subject, allowedIdsPattern)) when subject.getPrincipals().size() == 0 — i.e. the Subject was created empty or the JAAS login that should populate it never ran or failed silently.","commonSituations":"Broker started with sasl authentication enabled but missing/mislocated jaas.conf (java.security.auth.login.config not set or wrong path); JAAS config file lacks the expected login context (e.g. PulsarBroker entry) or uses a non-Kerberos LoginModule; keytab path or principal name in jaas.conf is wrong so login produced an empty Subject; KDC unreachable causing a failed login treated as empty subject.","solutions":["Set -Djava.security.auth.login.config=/path/to/broker_jaas.conf with a valid Kerberos entry (useKeyTab=true keyTab=... principal='broker/_HOST@REALM') and restart the broker","Verify the principal and keytab: run klist -k on the keytab and confirm the principal exists in the KDC; fix useKeyTab/keyTab/principal values in jaas.conf","Confirm the JAAS login actually succeeded at startup (check broker logs for LoginException during AuthenticationProviderSasl initialization); fix KDC connectivity (DNS, /etc/krb5.conf)","If running without Kerberos intentionally, switch the authentication provider instead of using SASL/GSSAPI"],"exampleFix":"// before (broker_env)\n# PULSAR_EXTRA_OPTS left without JAAS config\n// after\nPULSAR_EXTRA_OPTS=\"${PULSAR_EXTRA_OPTS} -Djava.security.auth.login.config=/etc/pulsar/broker_jaas.conf\"\n# broker_jaas.conf\nPulsarBroker {\n  com.sun.security.auth.module.Krb5LoginModule required\n  useKeyTab=true keyTab=\"/etc/security/keytabs/broker.keytab\"\n  principal=\"broker/myhost.foo.com@EXAMPLE.COM\" storeKey=true;\n};","handlingStrategy":"validation","validationCode":"// before constructing PulsarSaslServer\nSubject serverSubject = loginContext.getSubject();\nif (serverSubject == null || serverSubject.getPrincipals().isEmpty()) {\n    throw new IOException(\"No principals in server subject: check java.security.auth.login.config and the JAAS keytab entry\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    PulsarSaslServer server = new PulsarSaslServer(subject, allowedIdsPattern);\n} catch (SaslException e) {\n    if (e.getMessage().contains(\"server not have Principals\")) {\n        // fail broker startup with a config-guidance message\n        throw new IllegalStateException(\"Kerberos JAAS login produced no principals; verify -Djava.security.auth.login.config, keytab path and principal\", e);\n    }\n    throw e;\n}","preventionTips":["Always set -Djava.security.auth.login.config to a JAAS file with a valid Krb5LoginModule keytab entry before enabling SASL auth","Verify the keytab with klist -kt and test with kinit -kt before broker startup","Check broker startup logs for LoginException from the JAAS login; treat an empty Subject as fatal","Validate the principal name format (service/hostname@REALM) matches the keytab entry"],"tags":["sasl","kerberos","authentication","broker-startup"],"backgroundTag":"missing-kerberos-principal","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}