Skip to content

Kerberos authenticator sends 403 and bypasses auth chain when hadoop.auth cookie has been cleared to empty value #19519

@rzepinskip

Description

@rzepinskip

Affected Version

Druid 35.x (confirmed), likely all versions with druid-kerberos extension.

Description

When using a mixed authenticator chain of ["ldap", "kerberos"] (or any chain where Kerberos is not the only authenticator), users accessing the web console encounter an HTTP 403 error after their Kerberos authentication session expires:

HTTP ERROR 403 org.apache.hadoop.security.authentication.util.SignerException: Invalid signed text:
URI:    /unified-console.html
STATUS: 403
MESSAGE: org.apache.hadoop.security.authentication.util.SignerException: Invalid signed text:

Clearing all browser cookies for the Druid hostname resolves the issue temporarily. Simply setting the hadoop.auth cookie to empty does not reproduce the issue, because the browser will also attempt SPNEGO negotiation in that case — the real problem is described below.


Root cause — two interacting bugs:

Bug 1: Cookie "clear" does not instruct the browser to delete the cookie.

When a Kerberos-authenticated session ends (token expiry, SPNEGO failure, or any unauthenticated request), doFilterSuper in KerberosAuthenticator calls:

tokenToAuthCookie(httpResponse, "", getCookieDomain(), getCookiePath(), 0, false, isHttps);

The resulting Set-Cookie header is:

hadoop.auth=; Path=/; HttpOnly

No Max-Age=0 or past Expires directive is included. Browsers treat this as setting a session cookie with an empty value rather than deleting the cookie. On subsequent requests, the browser keeps sending hadoop.auth= (empty value).

Bug 2: An empty cookie value short-circuits the entire authenticator chain with a 403.

In KerberosAuthenticator.getToken(), the cookie value is passed directly to Signer.verifyAndExtract() without checking whether it is empty:

tokenStr = cookie.getValue();  // ""
tokenStr = mySigner.verifyAndExtract(tokenStr);  // throws SignerException: "Invalid signed text:"

Signer.verifyAndExtract("") throws SignerException because the empty string contains no &s= signature separator. This exception is caught and stored as authenticationEx. Later in doFilterSuper:

if (authenticationEx == null) {
    filterChain.doFilter(request, response);  // pass to next authenticator (e.g. LDAP)
} else {
    httpResponse.sendError(errCode, authenticationEx.getMessage());  // 403, chain bypassed
}

Because authenticationEx is non-null, the filter immediately sends a 403 error and never passes the request to other authenticators in the chain. In a ["ldap", "kerberos"] setup, the LDAP authenticator never gets a chance to handle the request, so the user cannot recover by entering their LDAP credentials — they see a 403 with no login prompt.


Reproduction steps:

  1. Configure Druid with an authenticator chain that includes both LDAP and Kerberos (e.g. druid.auth.authenticatorChain=["ldap","kerberos"] with skipOnFailure=true on both).
  2. Log in to the Druid web console via SPNEGO/Kerberos. The browser receives a signed hadoop.auth cookie (valid for ~10 hours by default).
  3. Wait for the Kerberos authentication token to expire (default: 36000 seconds / 10 hours).
  4. Attempt to access any Druid UI page (e.g. /unified-console.html).
  5. Observe HTTP 403 with SignerException: Invalid signed text:.
  6. Check browser cookies — hadoop.auth is present with an empty value.

Workaround: Manually delete (not clear) the hadoop.auth browser cookie for the Druid hostname.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions