Search code examples
javakerberoskerberos-delegationkeytab

KrbException: S4U2self needs a FORWARDABLE ticket


I am trying to perform kerberos constrained delegation through my java code. I've a keytab file, SPN attached to the user, and the delegation enabled for the SPN to that user. When I am trying to login with Keytab, I am getting the SPN's TGT. However, the "forwardable" flag is set to false on this ticket.

In order to impersonate the other user, I need this flag set to true.

Note: ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION flag is set on the SPN user.

Any help is highly appreciated.

private void tryKrb5Module() throws LoginException {
        System.setProperty("sun.security.krb5.debug", "true");
        System.setProperty("javax.security.auth.useSubjectCredsOnly","true");//has no impact

        final Subject subject = new Subject();
        final Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
        final Map<String,String> optionMap = new HashMap<String,String>();

        optionMap.put("keyTab", "c:\\ticket\\delegationUser.keytab");
        optionMap.put("principal", "TEST/TEST"); // default realm
        optionMap.put("doNotPrompt", "true");
        optionMap.put("refreshKrb5Config", "true");
        optionMap.put("useTicketCache", "true");
        optionMap.put("renewTGT", "true");
        optionMap.put("useKeyTab", "true");
        optionMap.put("storeKey", "true");
        optionMap.put("isInitiator", "true");


        krb5LoginModule.initialize(subject, null, new HashMap<String,String>(), optionMap);

        boolean loginOk = krb5LoginModule.login();
        System.out.println("======= login:  " + loginOk);

        boolean commitOk = krb5LoginModule.commit();
        System.out.println("======= commit: " + commitOk);

        System.out.println("======= Principal from subject: " + subject.getPrincipals());

    }

Solution

  • I figured out the solution. You need to set the krb config file in the system path. Then only the ticket obtained from the keytab is "forwardaable". Surprisingly, this is not mentioned anywhere clearly.

    System.setProperty("java.security.krb5.conf", "path_to_krb_config");

    Also make sure you have mentioned "forwardable = true" in your krb config file. Pasting example krb config file below:

    [libdefaults]
    default_realm = DOMAIN.COM
    default_tkt_enctypes = aes128-cts aes128-cts-hmac-sha1-96 aes256-cts aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
    default_tgs_enctypes = aes128-cts aes128-cts-hmac-sha1-96 aes256-cts aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
    permitted_enctypes = aes128-cts aes128-cts-hmac-sha1-96 aes256-cts aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
    dns_lookup_kdc = true
    dns_lookup_realm = false
    forwardable = true
    
    [realms]
        DOMAIN.COM = {
            kdc = KDC_HOST.DOMAIN.COM
            admin_server = KDC_HOST.DOMAIN.COM
            default_domain = DOMAIN.COM
        }
    
    [domain_realms]
        domain.com = DOMAIN.COM
        .domain.com = DOMAIN.COM