Search code examples
javaauthenticationkerberosjaas

Why is my program failing to create a new JAAS Login Context?


After doing some reading of the JAAS (Java Authentication and Authorization) documentation, I have tried to implement a simple test-case of Kerberos authentication in my Java application using JAAS. I am trying to authenticate against my company's AD server, as I want my application to approve and log the username of users using it to prevent unauthorized access.

As per the documentation here, I created the test class below. This test class is contained within an executable JAR that instantiates a copy of AuthTest during it's normal execution (thus kicking off the constructor code). I'm executing the jar with java -jar TheJar.jar -Djava.security.auth.login.config=auth.conf, and auth.conf is a JAAS Login config file that exists in the same directory as the jar file.

Class:

package main.java.***********.auth;

import com.sun.security.auth.callback.TextCallbackHandler;
import com.sun.security.auth.login.ConfigFile;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import javax.security.auth.login.*;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

/**
 *
 * @author
 */
public class AuthTest {
    static final Logger logger = LogManager.getLogger();

    Configuration.Parameters params = null;
    ConfigFile ConfigObj;
    TextCallbackHandler handler;

    public AuthTest(){
        //Try to create Login Context
        LoginContext lc = null;

        try{ //try #1
            lc = new LoginContext("TheJar", handler);
            logger.debug("LoginContext:" + lc.toString());
        }
        catch(LoginException le){
            logger.error(le.getMessage());
            logger.error(le.getCause());
        }

        //ENSURE Non-null context
        if (lc == null){
            logger.fatal("LOGIN CONTEXT WAS NULL. PROGRAM MUST DIE");
            System.exit(-1);
        }

        //Try To Login
        try{ //try #2
           lc.login(); 
        }
        catch(LoginException le){
            logger.error(le.getMessage());
            logger.error(le.getCause());
            logger.fatal("Authentication Failed. Shutting Down");
            System.exit(-1);
        }
    }
}

auth.conf:

TheJar { 
    com.sun.security.auth.module.Krb5LoginModule required;
    };

The problem, however, is that lc = new LoginContext("TheJar", handler); is failing and and calling the catch block beneath it. Being fairly new to Java and having never worked with any kind of Authentication components or software before, I'm really not sure what I'm doing wrong. The program keeps exiting with (ie: LOGIN CONTEXT WAS NULL. PROGRAM MUST DIE), so I know that try #1 is failing and--as mentioned--I believe that the lc = new LoginContext line to to blame. What am I doing wrong here?

Also, how can I tell for sure that my application is using auth.config at runtime? (EDIT: I figured out the answer to this sub-question: the java.security.auth.login.config setting set by the command line is actually a System property. Therefore, like all other System properties it can be accessed by using System.getProperty("java.security.auth.login.config")


Solution

  • I forgot to initialize the TextCallbackHandler handler.

    When I finally got a grip, I realized that I was supposed to be outputting the login error cause (le.getCause) to a debug message. Sure enough, staring me in the face was "invalid null CallbackHandler provided".

    I don't know how I didn't see it before, but providing a null (uninitialized) CallbackHandler was causing the LoginContext creation to fail. Fortunately though, coming to SO turned me on to this gem regarding JAAS: JAAS for human beings