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
- Only feed tokens taken from the Authorization header of a genuine client SPNEGO handshake (always an AP-REQ)
- Handle upstream Kerberos errors (clock skew, unknown principal) so KRB-ERROR tokens never reach this parser
- 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
- Only parse tokens from genuine client SPNEGO handshakes
- Fix upstream Kerberos failures (clock skew, unknown principal) so KRB-ERROR never reaches parsing
- Never replay captured non-AP-REQ traffic into this API
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
- Malformed gss token
- Tag not found: 0x${tags}
- Invalid SPNEGO sequence, 'WWW-Authenticate' header incorrect
- Invalid SPNEGO sequence, status code: {}
- oidName: ${oidName} is not supported.
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/30360df0c2b981e2.
Report an issue: GitHub.