JDK-8239385 : Support the 'canonicalize' setting (krb5.conf) in the Kerberos client
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.security
  • Affected Version: 8u241,11.0.6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux_ubuntu
  • CPU: x86_64
  • Submitted: 2020-02-14
  • Updated: 2021-01-13
  • Resolved: 2020-05-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 15 JDK 8 Other
11-poolResolved 15 b22Fixed 8u270Resolved openjdk8u272Fixed
Related Reports
Blocks :  
CSR :  
Duplicate :  
Relates :  
Sub Tasks
JDK-8242059 :  
JDK-8242409 :  
Description
As described in the CSR [JDK-8241871], the Kerberos client does not currently support the 'canonicalize' setting in the configuration file (krb5.conf). As a result, Name Canonicalization behavior (described by RFC 6806) cannot be customized: the client will claim support for it in every TGT request if sun.security.krb5.disableReferrals is false, and the KDC service may change the client name. Even though this is RFC-compliant, it can be unexpected for some clients as we can see in the report below:

---------------------------------------------------------

ADDITIONAL SYSTEM INFORMATION :
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"

$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~18.04-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)

A DESCRIPTION OF THE PROBLEM :
With 1.8.0_242 "client:" refers to the sAMAccountName of the object in AD, with 1.8.0_232 it used to refer to the servicePrincipalName (which is now "client alias:")

>>> DEBUG: ----Credentials----
       client: $V9H200-TAD2F4IK2G09@EXAMPLE.COM
       client alias: kafka/fqdn.example.com@EXAMPLE.COM
       server: zookeeper/fqdn.example.com@EXAMPLE.COM
       ticket: sname: zookeeper/fqdn.example.com@EXAMPLE.COM
       startTime: 1580465010000
       endTime: 1580501010000
       ----Credentials end----

So in some way with 1.8.0_232 zookeeper authenticated kafka/fqdn.example.com@EXAMPLE.COM while with 1.8.0_242 it is $V9H200-TAD2F4IK2G09@EXAMPLE.COM which leads to ACL problems in zookeeper.

REGRESSION : Last worked in version 8

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
# This is what we have:

user@host:~/work$ ls -al
total 20
drwxrwx--- 2 user user 4096 Feb 14 17:33 .
drwxr-xr-x 5 user user 4096 Feb 14 17:29 ..
-rw-rw---- 1 user user  942 Feb 14 17:29 KerberosDemo.java
-rw-rw---- 1 user user  101 Feb 13 13:13 jaas_cached.conf
-rw-rw---- 1 user user  276 Feb 13 13:24 jaas_keytab.conf


# it's a minimal example

user@host:~/work$ cat KerberosDemo.java 
import javax.security.auth.login.*;
import java.util.Iterator;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;

public class KerberosDemo {
        public static void main (String[] args) {
                LoginContext loginContext = null;
                try {
                        loginContext = new LoginContext("Demo");
                }
                catch (LoginException e) {
                        System.err.println("login context creation failed: "+e.getMessage());
                        System.exit(1);
                }
                try {
                        loginContext.login();
                }
                catch (LoginException e) {
                        System.out.println("authentication failed");
                        System.exit(1);
                }
                Subject subject = loginContext.getSubject();
                System.out.println("Authenticated principal: " + subject.getPrincipals());
                Set credentials = subject.getPrivateCredentials();
                Iterator iterator = credentials.iterator();
                KerberosTicket kt = (KerberosTicket) iterator.next();
                System.out.println("Client name: " + kt.getClient());
        }
}


# let's compile it

user@host:~/work$ javac KerberosDemo.java


# and use it either with a keytab (JAAS is getting the ticket) ...

user@host:~/work$ cat jaas_keytab.conf # use keytab!
Demo {
    com.sun.security.auth.module.Krb5LoginModule required
    useKeyTab=true
    keyTab="/etc/security/keytabs/myprincipal.service.keytab"
    storeKey=true
    useTicketCache=false
    serviceName="serviceprincipal"
    principal="myprincipal/fqdn.example.com@EXAMPLE.COM";
};


# ... or with a ticket gotten earlier by MIT Kerberos client (kinit)

user@host:~/work$ cat jaas_cached.conf # use cached!
Demo {
    com.sun.security.auth.module.Krb5LoginModule required
    useKeyTab=false
    useTicketCache=true;
};


# this is how the ticket was placed in the cache

user@host:~/work$ kinit -kt /etc/security/keytabs/myprincipal.service.keytab myprincipal/fqdn.example.com@EXAMPLE.COM


# now, this is what happens with OpenJDK 1.8.0_232
# principal name and client name all refer to myprincipal/fqdn.example.com@EXAMPLE.COM (in AD, this is the servicePrincipalName):

user@host:~/work$ java -version
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-0ubuntu1~18.04.1-b09)
OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode)
user@host:~/work$ java -Djava.security.auth.login.config=jaas_keytab.conf KerberosDemo
Authenticated principal: [myprincipal/fqdn.example.com@EXAMPLE.COM]
Client name: myprincipal/fqdn.example.com@EXAMPLE.COM
user@host:~/work$ java -Djava.security.auth.login.config=jaas_cached.conf KerberosDemo
Authenticated principal: [myprincipal/fqdn.example.com@EXAMPLE.COM]
Client name: myprincipal/fqdn.example.com@EXAMPLE.COM


# while this is what we see with OpenJDK 1.8.0_242
# while for the cached ticket the results are the same, for the ticket gotten by JAAS the names differ!!!
# Note: $V9H200-TAD2F4IK2G09 is the sAMAccountName of the AD user with servicePrincipalName myprincipal/fqdn.example.com@EXAMPLE.COM

user@host:~/work$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-8u242-b08-0ubuntu3~18.04-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)
user@host:~/work$ java -Djava.security.auth.login.config=jaas_keytab.conf KerberosDemo
Authenticated principal: [myprincipal/fqdn.example.com@EXAMPLE.COM]
Client name: $V9H200-TAD2F4IK2G09@EXAMPLE.COM
user@host:~/work$ java -Djava.security.auth.login.config=jaas_cached.conf KerberosDemo
Authenticated principal: [myprincipal/fqdn.example.com@EXAMPLE.COM]
Client name: myprincipal/fqdn.example.com@EXAMPLE.COM

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1.8.0_232 should behave the same as 1.8.0_242 so we can still run kafka/zookeeper.
ACTUAL -
When debugging Krb5 in Kafka/Zookeeper using OpenJDK 1.8.0_242 (this is where this bug hit me in the first place), the differing parts show up like this:

>>> DEBUG: ----Credentials----
       client: $V9H200-TAD2F4IK2G09@EXAMPLE.COM
       client alias: kafka/fqdn.example.com@EXAMPLE.COM
       server: zookeeper/fqdn.example.com@EXAMPLE.COM
       ticket: sname: zookeeper/fqdn.example.com@EXAMPLE.COM
       startTime: 1580465010000
       endTime: 1580501010000
       ----Credentials end----

So in some way with 1.8.0_232 zookeeper authenticated kafka/fqdn.example.com@EXAMPLE.COM while with 1.8.0_242 it is $V9H200-TAD2F4IK2G09@EXAMPLE.COM which leads to ACL problems in zookeeper.

---------- BEGIN SOURCE ----------
import javax.security.auth.login.*;
import java.util.Iterator;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosTicket;

public class KerberosDemo {
        public static void main (String[] args) {
                LoginContext loginContext = null;
                try {
                        loginContext = new LoginContext("Demo");
                }
                catch (LoginException e) {
                        System.err.println("login context creation failed: "+e.getMessage());
                        System.exit(1);
                }
                try {
                        loginContext.login();
                }
                catch (LoginException e) {
                        System.out.println("authentication failed");
                        System.exit(1);
                }
                Subject subject = loginContext.getSubject();
                System.out.println("Authenticated principal: " + subject.getPrincipals());
                Set credentials = subject.getPrivateCredentials();
                Iterator iterator = credentials.iterator();
                KerberosTicket kt = (KerberosTicket) iterator.next();
                System.out.println("Client name: " + kt.getClient());
        }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
There are two workarounds:

1. Changing the JAAS config to use a ticket in the ticket cache created upfront using kinit. However this workaround can't be used in automated environments where clients authenticate themselves using keytabs.

2. Downgrade from OpenJDK 8 Update 242 to Update 232. Using the same configuration, the principal is authenticated as kafka/fqdn.example.com@EXAMPLE.COM. However, downgrading a package can only be a temporary solution.

FREQUENCY : always



Comments
Requested the submitter verify the fix with latest version of JDK 15 and 16.
13-11-2020

I've requested a separated CSR for 8u. No differences with JDK-11 or mainline CSRs, though.
21-07-2020

Is the expectation for the 8u CSR to be different from the 11u CSR? If not, we should change the fix version for the CSR JDK-8244465 to include 8 and be done with it.
21-07-2020

Fix Request (8u) I would like to backport this to 8u for parity with Oracle 8u271. Original patch applies cleanly after JDK-8249610
16-07-2020

As stated in the review thread, a CSR should be filed and finalised before this is approved for 8u.
15-07-2020

Hi, I'll push to 11u-dev, as this was not a 'critical' request.
03-06-2020

Hi Martin, will you push this to jdk-updates/jdk11u? or to jdk11u-dev?
03-06-2020

Fix request (11u) JDK-11 is affected by this bug so a backport of the fix would be desirable. CSR for 11 has been approved. Patch applies cleanly. No regressions found in jdk/sun/security/krb5. Only the Kerberos client is affected by this patch. Even though the default 'canonicalize' behavior will be changed for TGT requests (as described in the CSR), this change will make it not only more backward-compatible but also aligned to MIT's Kerberos client behavior.
06-05-2020

URL: https://hg.openjdk.java.net/jdk/jdk/rev/142d090cab77 User: mbalao Date: 2020-05-05 18:07:08 +0000
05-05-2020

RFR thread: https://mail.openjdk.java.net/pipermail/security-dev/2020-March/021494.html
29-03-2020