Source Code for JAAS and Java GSS-API Tutorials

SampleServer.java

import org.ietf.jgss.*;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;

/**
 * A sample server application that uses JGSS to do mutual authentication
 * with a client using Kerberos as the underlying mechanism. It then
 * exchanges data securely with the client.
 *
 * Every message exchanged with the client includes a 4-byte application-
 * level header that contains the big-endian integer value for the number
 * of bytes that will follow as part of the JGSS token.
 *
 * The protocol is:
 *    1.  Context establishment loop:
 *         a. client sends init sec context token to server
 *         b. server sends accept sec context token to client
 *         ....
 *    2. client sends a wrap token to the server.
 *    3. server sends a mic token to the client for the application
 *       message that was contained in the wrap token.
 */

public class SampleServer  {

    public static void main(String[] args)
        throws IOException, GSSException {

        // Obtain the command-line arguments and parse the port number

        if (args.length != 1) {
            System.err.println("Usage: java <options> Login SampleServer <localPort>");
            System.exit(-1);
        }

        int localPort = Integer.parseInt(args[0]);

        ServerSocket ss = new ServerSocket(localPort);

        GSSManager manager = GSSManager.getInstance();

        while (true) {

            System.out.println("Waiting for incoming connection...");

            Socket socket = ss.accept();
            DataInputStream inStream =
                new DataInputStream(socket.getInputStream());
            DataOutputStream outStream =
                new DataOutputStream(socket.getOutputStream());

            System.out.println("Got connection from client "
                               + socket.getInetAddress());

            /*
             * Create a GSSContext to receive the incoming request
             * from the client. Use null for the server credentials
             * passed in. This tells the underlying mechanism
             * to use whatever credentials it has available that
             * can be used to accept this connection.
             */
            GSSContext context = manager.createContext((GSSCredential)null);

            // Do the context eastablishment loop

            byte[] token = null;

            while (!context.isEstablished()) {

                token = new byte[inStream.readInt()];
                System.out.println("Will read input token of size "
                                   + token.length
                                   + " for processing by acceptSecContext");
                inStream.readFully(token);

                token = context.acceptSecContext(token, 0, token.length);

                // Send a token to the peer if one was generated by
                // acceptSecContext
                if (token != null) {
                    System.out.println("Will send token of size "
                                       + token.length
                                       + " from acceptSecContext.");
                    outStream.writeInt(token.length);
                    outStream.write(token);
                    outStream.flush();
                }
            }

            System.out.print("Context Established! ");
            System.out.println("Client is " + context.getSrcName());
            System.out.println("Server is " + context.getTargName());
            /*
             * If mutual authentication did not take place, then
             * only the client was authenticated to the
             * server. Otherwise, both client and server were
             * authenticated to each other.
             */
            if (context.getMutualAuthState())
                System.out.println("Mutual authentication took place!");

            /*
             * Create a MessageProp which unwrap will use to return
             * information such as the Quality-of-Protection that was
             * applied to the wrapped token, whether or not it was
             * encrypted, etc. Since the initial MessageProp values
             * are ignored, just set them to the defaults of 0 and false.
             */
            MessageProp prop = new MessageProp(0, false);

            /*
             * Read the token. This uses the same token byte array
             * as that used during context establishment.
             */
            token = new byte[inStream.readInt()];
            System.out.println("Will read token of size "
                               + token.length);
            inStream.readFully(token);

            byte[] bytes = context.unwrap(token, 0, token.length, prop);
            String str = new String(bytes);
            System.out.println("Received data \""
                               + str + "\" of length " + str.length());

            System.out.println("Confidentiality applied: "
                               + prop.getPrivacy());

            /*
             * Now generate a MIC and send it to the client. This is
             * just for illustration purposes. The integrity of the
             * incoming wrapped message is guaranteed irrespective of
             * the confidentiality (encryption) that was used.
             */

            /*
             * First reset the QOP of the MessageProp to 0
             * to ensure the default Quality-of-Protection
             * is applied.
             */
            prop.setQOP(0);

            token = context.getMIC(bytes, 0, bytes.length, prop);

            System.out.println("Will send MIC token of size "
                               + token.length);
            outStream.writeInt(token.length);
            outStream.write(token);
            outStream.flush();

            System.out.println("Closing connection with client "
                               + socket.getInetAddress());
            context.dispose();
            socket.close();
        }
    }
}

bcsLogin.conf

/** 
 * Login Configuration for JAAS.
 */

com.sun.security.jgss.initiate {
  com.sun.security.auth.module.Krb5LoginModule required;
};

com.sun.security.jgss.accept {
  com.sun.security.auth.module.Krb5LoginModule required storeKey=true; 
};

SampleClient.java

import org.ietf.jgss.*;
import java.net.Socket;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;

/**
 * A sample client application that uses JGSS to do mutual authentication
 * with a server using Kerberos as the underlying mechanism. It then
 * exchanges data securely with the server.
 *
 * Every message sent to the server includes a 4-byte application-level
 * header that contains the big-endian integer value for the number
 * of bytes that will follow as part of the JGSS token.
 *
 * The protocol is:
 *    1.  Context establishment loop:
 *         a. client sends init sec context token to server
 *         b. server sends accept sec context token to client
 *         ....
 *    2. client sends a wrap token to the server.
 *    3. server sends a MIC token to the client for the application
 *       message that was contained in the wrap token.
 */

public class SampleClient {

    public static void main(String[] args)
       throws IOException, GSSException  {

        // Obtain the command-line arguments and parse the port number

        if (args.length < 3) {
            System.err.println("Usage: java <options> Login SampleClient "
                               + " <server> <hostName> <port>");
            System.exit(-1);
        }

        String server = args[0];
        String hostName = args[1];
        int port = Integer.parseInt(args[2]);

        Socket socket = new Socket(hostName, port);
        DataInputStream inStream =
          new DataInputStream(socket.getInputStream());
        DataOutputStream outStream =
          new DataOutputStream(socket.getOutputStream());

        System.out.println("Connected to server "
                           + socket.getInetAddress());

        /*
         * This Oid is used to represent the Kerberos version 5 GSS-API
         * mechanism. It is defined in RFC 1964. We will use this Oid
         * whenever we need to indicate to the GSS-API that it must
         * use Kerberos for some purpose.
         */
        Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");

        GSSManager manager = GSSManager.getInstance();

        /*
         * Create a GSSName out of the server's name. The null
         * indicates that this application does not wish to make
         * any claims about the syntax of this name and that the
         * underlying mechanism should try to parse it as per whatever
         * default syntax it chooses.
         */
        GSSName serverName = manager.createName(server, null);

        /*
         * Create a GSSContext for mutual authentication with the
         * server.
         *    - serverName is the GSSName that represents the server.
         *    - krb5Oid is the Oid that represents the mechanism to
         *      use. The client chooses the mechanism to use.
         *    - null is passed in for client credentials
         *    - DEFAULT_LIFETIME lets the mechanism decide how long the
         *      context can remain valid.
         * Note: Passing in null for the credentials asks GSS-API to
         * use the default credentials. This means that the mechanism
         * will look among the credentials stored in the current Subject
         * to find the right kind of credentials that it needs.
         */
        GSSContext context = manager.createContext(serverName,
                                        krb5Oid,
                                        null,
                                        GSSContext.DEFAULT_LIFETIME);

        // Set the desired optional features on the context. The client
        // chooses these options.

        context.requestMutualAuth(true);  // Mutual authentication
        context.requestConf(true);  // Will use confidentiality later
        context.requestInteg(true); // Will use integrity later

        // Do the context eastablishment loop

        byte[] token = new byte[0];

        while (!context.isEstablished()) {

            // token is ignored on the first call
            token = context.initSecContext(token, 0, token.length);

            // Send a token to the server if one was generated by
            // initSecContext
            if (token != null) {
                System.out.println("Will send token of size "
                                   + token.length
                                   + " from initSecContext.");
                outStream.writeInt(token.length);
                outStream.write(token);
                outStream.flush();
            }

            // If the client is done with context establishment
            // then there will be no more tokens to read in this loop
            if (!context.isEstablished()) {
                token = new byte[inStream.readInt()];
                System.out.println("Will read input token of size "
                                   + token.length
                                   + " for processing by initSecContext");
                inStream.readFully(token);
            }
        }

        System.out.println("Context Established! ");
        System.out.println("Client is " + context.getSrcName());
        System.out.println("Server is " + context.getTargName());

        /*
         * If mutual authentication did not take place, then only the
         * client was authenticated to the server. Otherwise, both
         * client and server were authenticated to each other.
         */
        if (context.getMutualAuthState())
            System.out.println("Mutual authentication took place!");

        byte[] messageBytes = "Hello There!\0".getBytes();

        /*
         * The first MessageProp argument is 0 to request
         * the default Quality-of-Protection.
         * The second argument is true to request
         * privacy (encryption of the message).
         */
        MessageProp prop =  new MessageProp(0, true);

        /*
         * Encrypt the data and send it across. Integrity protection
         * is always applied, irrespective of confidentiality
         * (i.e., encryption).
         * You can use the same token (byte array) as that used when
         * establishing the context.
         */

        token = context.wrap(messageBytes, 0, messageBytes.length, prop);
        System.out.println("Will send wrap token of size " + token.length);
        outStream.writeInt(token.length);
        outStream.write(token);
        outStream.flush();

        /*
         * Now we will allow the server to decrypt the message,
         * calculate a MIC on the decrypted message and send it back
         * to us for verification. This is unnecessary, but done here
         * for illustration.
         */

        token = new byte[inStream.readInt()];
        System.out.println("Will read token of size " + token.length);
        inStream.readFully(token);
        context.verifyMIC(token, 0, token.length,
                          messageBytes, 0, messageBytes.length,
                          prop);

        System.out.println("Verified received MIC for message.");

        System.out.println("Exiting...");
        context.dispose();
        socket.close();
    }
}

JaasAcn.java

import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import com.sun.security.auth.callback.TextCallbackHandler;

/**
 * This JaasAcn application attempts to authenticate a user
 * and reports whether or not the authentication was successful.
 */
public class JaasAcn {

    public static void main(String[] args) {

        // Obtain a LoginContext, needed for authentication. Tell it
        // to use the LoginModule implementation specified by the
        // entry named "JaasSample" in the JAAS login configuration
        // file and to also use the specified CallbackHandler.
        LoginContext lc = null;
        try {
            lc = new LoginContext("JaasSample", new TextCallbackHandler());
        } catch (LoginException le) {
            System.err.println("Cannot create LoginContext. "
                + le.getMessage());
            System.exit(-1);
        } catch (SecurityException se) {
            System.err.println("Cannot create LoginContext. "
                + se.getMessage());
            System.exit(-1);
        }

        try {

            // attempt authentication
            lc.login();

        } catch (LoginException le) {

            System.err.println("Authentication failed:");
            System.err.println("  " + le.getMessage());
            System.exit(-1);

        }

        System.out.println("Authentication succeeded!");

    }
}

jass.conf

/** Login Configuration for the JaasAcn and
 ** JaasAzn Applications 
 **/

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

jassacn.policy

/** Java Access Control Policy for the JaasAcn Application **/


grant codebase "file:./JaasAcn.jar" {

   permission javax.security.auth.AuthPermission "createLoginContext.JaasSample";
};

JaasAzn.java

import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import com.sun.security.auth.callback.TextCallbackHandler;
import java.security.PrivilegedAction;

/**
 * This JaasAzn application attempts to authenticate a user
 * and reports whether or not the authentication was successful.
 * If successful, it then sets up subsequent execution of
 * code in the run method of the SampleAction class such that
 * access control checks for security-sensitive operations will be
 * based on the user running the code.
 */
public class JaasAzn {

    public static void main(String[] args) {

        // Obtain a LoginContext, needed for authentication. Tell it
        // to use the LoginModule implementation specified by the
        // entry named "JaasSample" in the JAAS login configuration
        // file and to also use the specified CallbackHandler.
        LoginContext lc = null;
        try {
            lc = new LoginContext("JaasSample", new TextCallbackHandler());
        } catch (LoginException le) {
            System.err.println("Cannot create LoginContext. "
                + le.getMessage());
            System.exit(-1);
        } catch (SecurityException se) {
            System.err.println("Cannot create LoginContext. "
                + se.getMessage());
            System.exit(-1);
        }

        try {

            // attempt authentication
            lc.login();

        } catch (LoginException le) {

            System.err.println("Authentication failed:");
            System.err.println("  " + le.getMessage());
            System.exit(-1);

        }

        System.out.println("Authentication succeeded!");

        // now try to execute the SampleAction as the authenticated Subject
        Subject mySubject = lc.getSubject();
        PrivilegedAction action = new SampleAction();
        Subject.doAsPrivileged(mySubject, action, null);

    }
}

SampleAction.java

import java.io.File;
import java.security.PrivilegedAction;

/**
 * This is a sample PrivilegedAction implementation, designed to be
 * used with the JaasAzn class.
 */
public class SampleAction implements PrivilegedAction {

    /**
     * This sample PrivilegedAction performs the following operations:
     * <ul>
     * <li> Access the System property <i>java.home</i>
     * <li> Access the System property <i>user.home</i>
     * <li> Access the file <i>foo.txt</i>
     * </ul>
     *
     * @return <code>null</code> in all cases.
     *
     * @exception SecurityException if the caller does not have permission
     *          to perform any of the operations listed above.
     */
    public Object run() {
        System.out.println("\nYour java.home property value is: "
                            +System.getProperty("java.home"));

        System.out.println("\nYour user.home property value is: "
                            +System.getProperty("user.home"));

        File f = new File("foo.txt");
        System.out.print("\nfoo.txt does ");
        if (!f.exists())
            System.out.print("not ");
        System.out.println("exist in the current working directory.");
        return null;
    }
}

jassazn.policy

/** Java Access Control Policy for the JaasAzn Application **/

/** Code-Based Access Control Policy for JaasAzn **/

grant codebase "file:./JaasAzn.jar" {

   permission javax.security.auth.AuthPermission 
                    "createLoginContext.JaasSample";
   permission javax.security.auth.AuthPermission "doAsPrivileged";
};


/** User-Based Access Control Policy for the SampleAction class
 ** instantiated by JaasAzn 
 **/

grant	codebase "file:./SampleAction.jar",
    Principal javax.security.auth.kerberos.KerberosPrincipal 
        "your_user_name@your_realm"  {

   permission java.util.PropertyPermission "java.home", "read";
   permission java.util.PropertyPermission "user.home", "read";
   permission java.io.FilePermission "foo.txt", "read";
};

Login.java

import java.io.*;
import java.lang.reflect.*;
import java.util.Arrays;

import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.Subject;
import com.sun.security.auth.callback.TextCallbackHandler;

/**
 * <p> This class authenticates a <code>Subject</code> and then
 * executes a specified application as that <code>Subject</code>.
 * To use this class, the java interpreter would typically be invoked as:
 *
 * <pre>
 *    % java -Djava.security.manager \
 *        Login \
 *        <applicationclass> <applicationClass_args>
 * </pre>
 *
 * <p> <i>applicationClass</i> represents the application to be executed
 * as the authenticated <code>Subject</code>,
 * and <i>applicationClass_args</i> are passed as arguments to
 * <i>applicationClass</i>.
 *
 * <p> To perform the authentication, <code>Login</code> uses a
 * <code>LoginContext</code>.  A <code>LoginContext</code> relies on a
 * <code>Configuration</code> to determine the modules that should be used
 * to perform the actual authentication.  The location of the Configuration
 * is dependent upon each Configuration implementation.
 * The default Configuration implementation
 * (<code>com.sun.security.auth.login.ConfigFile</code>)
 * allows the Configuration location to be specified (among other ways)
 * via the <code>java.security.auth.login.config</code> system property.
 * Therefore, the <code>Login</code> class can also be invoked as:
 *
 * <pre>
 *    % java -Djava.security.manager \
 *        -Djava.security.auth.login.config=<configuration_url> \
 *        Login \
 *        <your_application_class> <your_application_class_args>
 * </pre>
 */

public class Login {

    /**
     * <p> Instantate a <code>LoginContext</code> using the
     * provided application classname as the index for the login
     * <code>Configuration</code>.  Authenticate the <code>Subject</code>
     * (three retries are allowed) and invoke
     * <code>Subject.doAsPrivileged</code>
     * with the authenticated <code>Subject</code> and a
     * <code>PrivilegedExceptionAction</code>.
     * The <code>PrivilegedExceptionAction</code>
     * loads the provided application class, and then invokes
     * its public static <code>main</code> method, passing it
     * the application arguments.
     *
     * <p>
     *
     * @param args the arguments for <code>Login</code>.  The first
     *          argument must be the class name of the application to be
     *          invoked once authentication has completed, and the
     *          subsequent arguments are the arguments to be passed
     *          to that application's public static <code>main</code> method.
     */
    public static void main(String[] args) {

        // check for the application's main class
        if (args == null || args.length == 0) {
            System.err.println("Invalid arguments: " +
                "Did not provide name of application class.");
            System.exit(-1);
        }

        LoginContext lc = null;
        try {
            lc = new LoginContext(args[0], new TextCallbackHandler());
        } catch (LoginException le) {
            System.err.println("Cannot create LoginContext. "
                + le.getMessage());
            System.exit(-1);
        } catch (SecurityException se) {
            System.err .println("Cannot create LoginContext. "
                + se.getMessage());
            System.exit(-1);
        }

        // the user has 3 attempts to authenticate successfully
        int i;
        for (i = 0; i < 3; i++) {
            try {

                // attempt authentication
                lc.login();

                // if we return with no exception, authentication succeeded
                break;

            } catch (AccountExpiredException aee) {

                System.err.println("Your account has expired.  " +
                                "Please notify your administrator.");
                System.exit(-1);

            } catch (CredentialExpiredException cee) {

                System.err.println("Your credentials have expired.");
                System.exit(-1);

            } catch (FailedLoginException fle) {

                System.err.println("Authentication Failed");
                try {
                      Thread.currentThread().sleep(3000);
                } catch (Exception e) {
                      // ignore
                }

            } catch (Exception e) {

                System.err.println("Unexpected Exception - unable to continue");
                e.printStackTrace();
                System.exit(-1);
            }
        }

        // did they fail three times?
        if (i == 3) {
            System.err.println("Sorry");
            System.exit(-1);
        }

        // push the subject into the current ACC
        try {
            Subject.doAsPrivileged(lc.getSubject(),
                                   new  MyAction(args),
                                   null);
        } catch (java.security.PrivilegedActionException pae) {
            pae.printStackTrace();
            System.exit(-1);
        }

        System.exit(0);
    }
}

class MyAction implements java.security.PrivilegedExceptionAction {

    String[] origArgs;

    public MyAction(String[] origArgs) {
        this.origArgs = (String[])origArgs.clone();
    }

    public Object run() throws Exception {

        // get the ContextClassLoader
        ClassLoader cl = Thread.currentThread().getContextClassLoader();

        try {
            // get the application class's main method
            Class c = Class.forName(origArgs[0], true, cl);
            Class[] PARAMS = { origArgs.getClass() };
            java.lang.reflect.Method mainMethod = c.getMethod("main", PARAMS);

            // invoke the main method with the remaining args
            String[] appArgs = new String[origArgs.length - 1];
            System.arraycopy(origArgs, 1, appArgs, 0, origArgs.length - 1);
            Object[] args = { appArgs };
            mainMethod.invoke(null /*ignored*/, args);
        } catch (Exception e) {
            throw new java.security.PrivilegedActionException(e);
        }

        // successful completion
        return null;
    }
}

Sample.java

import java.io.File;

public class Sample {

    /**
     * This sample class performs the following operations:
     * <ul>
     * <li> Access the System property <i>java.home</i>
     * <li> Access the System property <i>user.home</i>
     * <li> Access the file <i>foo.txt</i>
     * </ul>
     *
     * @exception SecurityException if the caller does not have permission
     *          to perform any of the operations listed above.
     */
    public static void main (String[] args) throws SecurityException {

        // If there were any arguments to read, we'd do it here.

        System.out.println("\nYour java.home property value is: "
                            +System.getProperty("java.home"));

        System.out.println("\nYour user.home property value is: "
                            +System.getProperty("user.home"));

        File f = new File("foo.txt");
        System.out.print("\nfoo.txt does ");
        if (!f.exists())
            System.out.print("not ");
        System.out.println("exist in the current working directory.");
    }
}

sample.conf

/** Login Configuration for the Sample Application **/

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

sample.policy

/** Access Control Policy for the Sample Application **/


grant codebase "file:./Login.jar" {
   permission java.security.AllPermission;
};


grant	codebase "file:./Sample.jar",
    Principal javax.security.auth.kerberos.KerberosPrincipal 
        "your_user_name@your_realm"  {

   permission java.util.PropertyPermission "java.home", "read";
   permission java.util.PropertyPermission "user.home", "read";
   permission java.io.FilePermission "foo.txt", "read";
};

csLogin.conf

/** 
 * Login Configuration for JAAS.
 */

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

SampleServer {
  com.sun.security.auth.module.Krb5LoginModule required storeKey=true principal="service_principal@your_realm";
};

client.policy

grant CodeBase "file:./Login.jar" {
        permission java.security.AllPermission;
};

grant CodeBase "file:./SampleClient.jar", 
	Principal javax.security.auth.kerberos.KerberosPrincipal 
		"your_user_name@your_realm" {

	permission java.net.SocketPermission "*", "connect";

	permission javax.security.auth.kerberos.ServicePermission
		"krbtgt/your_realm@your_realm", 
		"initiate";

	permission javax.security.auth.kerberos.ServicePermission
		"service_principal@your_realm", 
		"initiate";
};

server.policy

grant CodeBase "file:./Login.jar" {
        permission java.security.AllPermission;
};

grant CodeBase "file:./SampleServer.jar" 
	Principal javax.security.auth.kerberos.KerberosPrincipal 
		"service_principal@your_realm" {

	permission java.net.SocketPermission "*", "accept";

	permission javax.security.auth.kerberos.ServicePermission
		"service_principal@your_realm", "accept";
};

SampleServerImp.java

import org.ietf.jgss.*;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
import javax.security.auth.Subject;
import java.security.PrivilegedAction;

/**
 * A sample server application that uses JGSS to do mutual authentication
 * with a client using Kerberos as the underlying mechanism. It then
 * exchanges data securely with the client.
 *
 * Every message exchanged with the client includes a 4-byte application-
 * level header that contains the big-endian integer value for the number
 * of bytes that will follow as part of the JGSS token.
 *
 * The protocol is:
 *    1.  Context establishment loop:
 *         a. client sends init sec context token to server
 *         b. server sends accept sec context token to client
 *         ....
 *    2. client sends a wrap token to the server.
 *    3. server sends a mic token to the client for the application
 *       message that was contained in the wrap token.
 */

public class SampleServerImp  {

    public static void main(String[] args)
        throws IOException, GSSException {

        // Obtain the command-line arguments and parse the port number

        if (args.length != 1) {
            System.err.println("Usage: java <options> Login SampleServer <localPort>");
            System.exit(-1);
        }

        int localPort = Integer.parseInt(args[0]);

        ServerSocket ss = new ServerSocket(localPort);

        GSSManager manager = GSSManager.getInstance();

        while (true) {

            System.out.println("Waiting for incoming connection...");

            Socket socket = ss.accept();
            DataInputStream inStream =
                new DataInputStream(socket.getInputStream());
            DataOutputStream outStream =
                new DataOutputStream(socket.getOutputStream());

            System.out.println("Got connection from client "
                               + socket.getInetAddress());

            /*
             * Create a GSSContext to receive the incoming request
             * from the client. Use null for the server credentials
             * passed in. This tells the underlying mechanism
             * to use whatever credentials it has available that
             * can be used to accept this connection.
             */
            GSSContext context = manager.createContext((GSSCredential)null);

            // Do the context eastablishment loop

            byte[] token = null;

            while (!context.isEstablished()) {

                token = new byte[inStream.readInt()];
                System.out.println("Will read input token of size "
                                   + token.length
                                   + " for processing by acceptSecContext");
                inStream.readFully(token);

                token = context.acceptSecContext(token, 0, token.length);

                // Send a token to the peer if one was generated by
                // acceptSecContext
                if (token != null) {
                    System.out.println("Will send token of size "
                                       + token.length
                                       + " from acceptSecContext.");
                    outStream.writeInt(token.length);
                    outStream.write(token);
                    outStream.flush();
                }
            }

            System.out.println("Context Established! ");
            System.out.println("Client is " + context.getSrcName());
            System.out.println("Server is " + context.getTargName());
            /*
             * If mutual authentication did not take place, then
             * only the client was authenticated to the
             * server. Otherwise, both client and server were
             * authenticated to each other.
             */
            if (context.getMutualAuthState())
                System.out.println("Mutual authentication took place!");

            /*
             * Create a MessageProp which unwrap will use to return
             * information such as the Quality-of-Protection that was
             * applied to the wrapped token, whether or not it was
             * encrypted, etc. Since the initial MessageProp values
             * are ignored, just set them to the defaults of 0 and false.
             */
            MessageProp prop = new MessageProp(0, false);

            /*
             * Read the token. This uses the same token byte array
             * as that used during context establishment.
             */
            token = new byte[inStream.readInt()];
            System.out.println("Will read token of size "
                               + token.length);
            inStream.readFully(token);

            byte[] bytes = context.unwrap(token, 0, token.length, prop);
            String str = new String(bytes);
            System.out.println("Received data \""
                               + str + "\" of length " + str.length());

            System.out.println("Confidentiality applied: "
                               + prop.getPrivacy());

            /*
             * Now generate a MIC and send it to the client. This is
             * just for illustration purposes. The integrity of the
             * incoming wrapped message is guaranteed irrespective of
             * the confidentiality (encryption) that was used.
             */

            /*
             * First reset the QOP of the MessageProp to 0
             * to ensure the default Quality-of-Protection
             * is applied.
             */
            prop.setQOP(0);

            token = context.getMIC(bytes, 0, bytes.length, prop);

            System.out.println("Will send MIC token of size "
                               + token.length);
            outStream.writeInt(token.length);
            outStream.write(token);
            outStream.flush();


            /*
             * Impersonate client
             */

            System.out.println("Impersonating client.");

            /*
             * Extract the KerberosPrincipal from the client GSSName and populate
             * it in the principal set of a new Subject. Pass in a null for
             * credentials. If we were to pass in the delegated GSSCredential
             * instead of null, then the resulting Subject's private credential
             * set would also be populated.
             */
            GSSName clientGSSName = context.getSrcName();
            System.out.println("clientGSSName: " + clientGSSName);
            Subject client =
                com.sun.security.jgss.GSSUtil.createSubject(clientGSSName,
                                                     null);

            /*
             * Construct an action that will read a file meant only for the
             * client
             */
            PrivilegedAction readFile =
                new ReadFileAction(clientGSSName.toString());

            /*
             * Invoke the action via a doAsPrivileged. This allows the
             * action to be executed as the client subject, and it also runs
             * that code as privileged. This means that any permission checking
             * that happens beyond this point applies only to the code being
             * run as the client.
             */
            Subject.doAsPrivileged(client, readFile, null);



            /*
             * Clean up
             */


            System.out.println("Closing connection with client "
                               + socket.getInetAddress());
            context.dispose();
            socket.close();
        }
    }
}

ReadFileAction.java

import java.security.PrivilegedAction;
import java.io.*;

/**
 * This class implements the PrivilegedAction interface to demonstrate the
 * reading of a file that belongs to the client. This code will be
 * executed by the server while impersonating the client principal.
 */
public class ReadFileAction implements PrivilegedAction {

    private String fileName;

    /**
     * Contructs a ReadFileAction instance.
     *
     * @param kerberosPrincipalName the name of the Kerberos principal
     * who owns the file that will be read. The filename is constructed
     * from the name of the principal.
     */
    public ReadFileAction(String kerberosPrincipalName) {
        /*
         * Separate the realm component from the name and use the rest of
         * it for constructing the filename. If the principal name is
         * "joe@REALM" then the file that will be read is
         * "data/joe_info.txt". The path separator "/" might be "\" in the
         * case of Windows.
         */
        int realmSeparatorPos = kerberosPrincipalName.lastIndexOf('@');
        fileName = "data" + File.separatorChar
            + kerberosPrincipalName.substring(0, realmSeparatorPos)
            + "_info.txt";
    }

    /**
     * Does the actual reading of the file. It displays the text contained
     * in the file.
     */
    public Object run() {
        System.out.println("===============================================");
        System.out.println("Reading file: " + fileName);
        try {
            BufferedReader reader = new BufferedReader(new FileReader(fileName));
            String str = reader.readLine();
            while (str != null) {
                System.out.println(str);
                str = reader.readLine();
            }
        } catch (IOException e) {
            System.err.println(e);
        }
        System.out.println("===============================================");
        return null;
    }
}

serverimp.policy

grant CodeBase "file:./Login.jar" {
        permission java.security.AllPermission;
};

grant CodeBase "file:./SampleServerImp.jar" 
	Principal javax.security.auth.kerberos.KerberosPrincipal 
		"service_principal@your_realm" {

	permission java.net.SocketPermission "*", "accept";

	permission javax.security.auth.kerberos.ServicePermission
		"service_principal@your_realm", "accept";

	permission javax.security.auth.AuthPermission "doAsPrivileged";
};

grant CodeBase "file:./ReadFileAction.jar" 
	Principal javax.security.auth.kerberos.KerberosPrincipal 
		"your_user_name@your_realm" {

	permission java.io.FilePermission 
		"data/your_user_name_info.txt", "read";
};

csImpLogin.conf

/** 
 * Login Configuration for JAAS.
 */

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

SampleServerImp {
  com.sun.security.auth.module.Krb5LoginModule required storeKey=true principal="service_principal@your_realm";
};