apache/hadoop · error · IllegalArgumentException

Not an AP-REQ token

Error message

Not an AP-REQ token

What it means

Inside KerberosUtil.getTokenServerName(), after the mechanism OID check passes, the first inner-context byte (token-id) must be 1, which identifies an AP-REQ — the message a client sends when presenting a Kerberos ticket. Any other tag (e.g. 0x0a KRB-ERROR, or a TGT-REQ) triggers IllegalArgumentException('Not an AP-REQ token').

Source

Thrown at hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/KerberosUtil.java:327

    if (oid.equals(DER.SPNEGO_MECH_OID)) {
      // NegotiationToken ::= CHOICE {
      //     neg-token-init[0] NegTokenInit
      // }
      // NegTokenInit ::= SEQUENCE {
      //     mech-token[2]     InitialContextToken
      // }
      token = token.next().get(0xa0, 0x30, 0xa2, 0x04).next();
      oid = token.next();
    }
    if (!oid.equals(DER.KRB5_MECH_OID)) {
      throw new IllegalArgumentException("Malformed gss token");
    }
    // InnerContextToken ::= {
    //     token-id[1]
    //     AP-REQ
    // }
    if (token.next().getTag() != 1) {
      throw new IllegalArgumentException("Not an AP-REQ token");
    }
    // AP-REQ ::= [APPLICATION 14] SEQUENCE {
    //     ticket[3]      Ticket
    // }
    DER ticket = token.next().get(0x6e, 0x30, 0xa3, 0x61, 0x30);
    // Ticket ::= [APPLICATION 1] SEQUENCE {
    //     realm[1]       String
    //     sname[2]       PrincipalName
    // }
    // PrincipalName ::= SEQUENCE {
    //     name-string[1] SEQUENCE OF String
    // }
    String realm = ticket.get(0xa1, 0x1b).getAsString();
    DER names = ticket.get(0xa2, 0x30, 0xa1, 0x30);
    StringBuilder sb = new StringBuilder();
    while (names.hasNext()) {
      if (sb.length() > 0) {
        sb.append('/');

View on GitHub (pinned to 2add963021)

Solutions

  1. Only feed tokens taken from the Authorization header of a genuine client SPNEGO handshake (always an AP-REQ)
  2. Handle upstream Kerberos errors (clock skew, unknown principal) so KRB-ERROR tokens never reach this parser
  3. Catch IllegalArgumentException and fail the authentication request with 401 rather than crashing the handler

Example fix

// before
String server = KerberosUtil.getTokenServerName(rawToken);

// after: guard with the documented unchecked exception
try {
  String server = KerberosUtil.getTokenServerName(rawToken);
} catch (IllegalArgumentException e) {
  response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid SPNEGO token");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// token-id byte must be 1 (AP-REQ); cheap pre-check after mech OID acceptance is impractical — validate at capture instead:
if (rawToken == null || rawToken.length < 10) throw new AuthenticationException("token too short");

Try / catch

try { KerberosUtil.getTokenServerName(raw); } catch (IllegalArgumentException e) { /* KRB-ERROR or wrong message type: 401 + Negotiate, log at debug */ }

Prevention

When it happens

Trigger: Passing a GSS token that wraps a KRB-ERROR (typical when the KDC rejected the client) or an AS-REQ/TGS-REQ instead of the AP-REQ a server receives during SPNEGO authentication.

Common situations: Replaying captured Kerberos traffic of the wrong message type into a test harness; server-side code invoked on error responses after clock skew or unknown-principal failures; protocol-level fuzzing.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/30360df0c2b981e2. Report an issue: GitHub.