Skip to content

GraalVM native image kerberos authentication issue: failed to store/retrieve AccessControlContext to/from stack  #2745

@zcui001

Description

@zcui001

GraalVM and environment:

  • OS: Linux
  • GraalVM version 20.1.0 (both CE and EE)
  • JDK: 1.8

Issue:
The same java application code for kerberos authentication works fine in JVM, but failed to get GSSCredential in native image. We noticed JVM and native image have different behavior when handling AccessControlContext.

Steps to reproduce:

  1. On Linux, run 'kinit -f' to retrieve valid kerberos ticket and store to the cache.
  2. build and run the blow java code:

import javax.security.auth.Subject;
import javax.security.auth.SubjectDomainCombiner;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.;
import java.util.
;

public static void kerberosTest() throws PrivilegedActionException, LoginException {

    class LoginConfiguration extends Configuration
    {
        private AppConfigurationEntry entry;
        private LoginConfiguration(Map<String, String> options)
        {
            entry = new AppConfigurationEntry(
                    "com.sun.security.auth.module.Krb5LoginModule",
                    AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
                    new HashMap<>(options)
            );
        }

        @Override
        public AppConfigurationEntry[] getAppConfigurationEntry(String name)
        {
            return new AppConfigurationEntry[] {entry};
        }
    }

    //Kerberos login and get subject
    Subject subject = null;
    Map<String, String> options = new HashMap<>();
    options.put("doNotPrompt", "true");
    options.put("useTicketCache", "true");
    Configuration configuration = new LoginConfiguration(options);
    LoginContext loginContext = new LoginContext("", null, null, configuration);
    loginContext.login();
    subject = loginContext.getSubject();


    Subject.doAs(subject, new PrivilegedExceptionAction<Boolean>() {
        @Override
        public Boolean run() throws Exception
        {
            final AccessControlContext acc = AccessController.getContext();

            DomainCombiner dc = acc.getDomainCombiner();

            //run the code in JVM will retrieve valid dc but native image will return null for dc
            if (dc == null ) {
                System.out.println("dc is null");
                return Boolean.FALSE;
            }
            System.out.println("dc is NOT null");

            return Boolean.TRUE;

        }
    });
}

Our analysis:
We debugged the code, and learned Subject.doAs(subject) is supposed to push a AccessControlContext with the subject to the stack and later the AccessController.getContext() will retrieve it. However, in native image, it failed to retrieve it from the stack. We noticed two native java methods were called in the process, so we add them to the jni-config.json as below, but it didn't help.
{
"name":"java.security.AccessController",
"methods":[
{"name":"doPrivileged","parameterTypes":["java.security.PrivilegedExceptionAction", "java.security.AccessControlContext"] },
{"name":"getStackAccessControlContext" }
]
},

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions