Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4633622

bug in LoginContext when Configuration is subclassed

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 1.4.1
    • 1.0
    • security-libs
    • hopper
    • x86
    • windows_2000
    • Verified



      Name: nt126004 Date: 02/05/2002


      FULL PRODUCT VERSION :
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
      Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)

      FULL OPERATING SYSTEM VERSION :

      Redhat 6.2
      Linux beta 2.2.17 #3 SMP Mon Sep 11 10:47:02 CDT 2000 i686
      unknown

      ADDITIONAL OPERATING SYSTEMS :

      Windows 2000


      A DESCRIPTION OF THE PROBLEM :
      This is a resubmission with complete test programs
      recreating problem.

      There appears to be a bug in the JAAS api involved in sub-
      classing the Configuration class. By default LoginContext
      uses the default implementation of Configuration
      (ConfigFile) to load modules and parameters. Each login
      module is then initalized when the login method of
      LoginContext is called. When using the default
      Configuration class, each instance of LoginContext results
      in a unique instance of each LoginModule.

      When the Configuration class is extended, the LoginContext
      class behaves differently. Rather than each new instance of
      LoginContext resulting in a new instance of LoginModule,
      only one instance of LoginModule is ever instantiated. The
      initalize method of LoginModule is only ever called once,
      therefore the same instance of CallbackHandler is executed
      resulting in the same data every time.

      We have recreated this on multiple operating systems and
      with different programs an subclasses.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Included is source code to recreate this bug.

      Three modules are included:

      AuthenticationConfiguration.java - this is the subclass of
      Configuration.

      GenericLoginModule.java - an extenstion of LoginModule that
      prints logic flow (as called by LoginContext)

      testJAASBug.java - a program ( with main ) to recreate the
      problem.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      a new instance of LoginContext should instantiate new
      LoginModule Objects. This works fine when using the
      defualt Configuration class. When using a subclass, only
      one instance of LoginModule is used.




      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package jaasconfigurationbug;

      /**
       * Title: JAAS Configuration Bug
       * Description: Project to demonstrate JAAS bug when dealing with subclassing
       * of Configuration
       * Copyright: Copyright (c) 2001
       * Company: Servzone.com
       * @author Richard Scott
       * @version 1.0
       */
      import javax.security.auth.*;
      import javax.security.auth.spi.*;
      import javax.security.auth.callback.*;
      import javax.security.auth.login.*;

      import java.security.*;

      public class TestJAASBug
      {

          public TestJAASBug()
          {
              // Initialize Configuration Class with subclass
              Configuration.setConfiguration(new AuthenticationConfiguration());
              // Now JAAS will use class "AuthenticationConfiguration"

              // Set a single LoginModule for JAAS to use
              AuthenticationConfiguration.addAppConfigurationEntry
      ("required", "jaasconfigurationbug.GenericLoginModule", "test=yes");
              System.out.println("Instance one of Login Context begin instantiated");
              // Instantiate the first LoginContext - the passed String does not
      matter because our Configuration subclass does not use it
              try
              {
                  LoginContext lc = new LoginContext("anything");
                  // and login
                  lc.login();
              }
              catch (LoginException le)
              {
                  le.printStackTrace();
              }

              // So far things have worked A-OK!!

              // Noe we have a second person needed to login to our server
              System.out.println("Instance two of Login Context begin instantiated");
              try
              {
                  LoginContext lc2 = new LoginContext("anythingelse");
                  // and login
                  lc2.login();
              }
              catch (LoginException le)
              {
                  le.printStackTrace();
              }

              // Note that the exact same Instance of GenericLoginModule Executes
              // And that initialize is not called again. the correct behavior is for
              // each new instance of LoginContext to instantiate a new instance of
              // LoginModule. This behavior works with the base Configuration class
              // but ALWAYS fails with a subclasse of Configuration.
          }



          public static void main(String[] args)
          {
              TestJAASBug test = new TestJAASBug();
          }
      }

      package jaasconfigurationbug;

      /**
       * Title:
       * Description:
       * Copyright: Copyright (c) 2001
       * Company:
       * @author
       * @version 1.0
       */

      import javax.security.auth.login.Configuration;
      import javax.security.auth.login.AppConfigurationEntry;
      import java.util.ArrayList;
      import java.util.StringTokenizer;
      import java.util.HashMap;

      public class AuthenticationConfiguration extends Configuration
      {
          private static ArrayList appConfigurationList = new ArrayList();

          public AuthenticationConfiguration()
          {
          }

          /**
           * Interface method requiring us to return all the LoginModules we
           * know about.
           */
          public AppConfigurationEntry[] getAppConfigurationEntry( String
      applicationName )
          {
              AppConfigurationEntry[] ace = new AppConfigurationEntry
      [appConfigurationList.size()];

              // Weird bug - Java would not le us use the toArray method of
              // appConfigurationList - would not cast properly
              for (int i=0;i < appConfigurationList.size();i++)
              {
                  ace[i] = (AppConfigurationEntry)appConfigurationList.get(i);
              }
              return ace;
          }

          /**
           * Interface method that requires us to reload the configuration.
           * This method is defined but there is no underluing implementation.
           */
          public void refresh()
          {
          // Right now this is a load once scheme and we will not implement the
          // refresh method
          }

          /**
           * Adds a new LoginModule entry from the configuration process
           */
          public static boolean addAppConfigurationEntry ( String flag, String
      module, String options )
          {
              AppConfigurationEntry.LoginModuleControlFlag lmcf;
              HashMap optionList = null;
              StringTokenizer st1 = null;
              StringTokenizer st2 = null;
              if ( flag.equals("required") )
              {
                  lmcf = AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
              }
              else if ( flag.equals("requisite") )
              {
                  lmcf = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
              }
              else if ( flag.equals("sufficient") )
              {
                  lmcf = AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
              }
              else if ( flag.equals("optional") )
              {
                  lmcf = AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
              }
              else
              {
                  return false;
              }

              st1 = new StringTokenizer( options, " ");
              optionList = new HashMap();
              //Walk through space delimited option list String
              // eg. option1=yes option2=no option3=true

              while (st1.hasMoreTokens())
              {
                  // get the second Stringtokenizer that seperates by equal sign (=)
                  st2 = new StringTokenizer( st1.nextToken(), "=");
                  // make sure there is only one equal sign (=) and
                  // send the two parts to the Map
                  if (st2.countTokens() == 2)
                  {
                      optionList.put(st2.nextToken() , st2.nextToken());
                  }
              }
              //finish up by adding a new entry to the appConfigurationList.
              return appConfigurationList.add( new AppConfigurationEntry(module,
      lmcf, optionList));
              }
          }

      package jaasconfigurationbug;

      /**
       * Title: ActiveConnect - Enterprise Edition
       * Description: JAAS compliant login module that authenticates useris and
       * passwords in the XML Realm
       * Copyright: Copyright (c) 2002
       * Company: Servzone.com, Inc.
       * @author Richard Scott
       * @version 1.0
       */

      import javax.security.auth.*;
      import javax.security.auth.spi.*;
      import javax.security.auth.callback.*;
      import javax.security.auth.login.*;

      import java.io.*;
      import java.security.*;
      import java.util.*;



      /**
       * Login module that checks a username and password.
       */
      public class GenericLoginModule implements LoginModule
      {

          private Subject subject;
          private CallbackHandler callbackHandler;

          private boolean loginSucceeded = false;
          private boolean commitSucceeded = false;

          private String userid;
          private char[] password;

          private Principal principal;

          /**
           * * Initialize this login module.
           */
          public void initialize(Subject subject,CallbackHandler callbackHandler,
              Map sharedState,Map options)
              {
                  System.out.println("Initialize method called for Object " + this);
              }

          /**
           * * Attempt to log a user in.
           */
          public boolean login() throws LoginException
          {
                  System.out.println("Login method called for" + this);
                  return true;
          }

          /**
           * * This is called if all logins succeeded.
           */
          public boolean commit() throws LoginException
          {
              System.out.println("Commit method called for Object " + this);
              return true;
          }

          /**
           * * Called if overall login failed.
           */
          public boolean abort() throws LoginException
          {
              System.out.println("Abort method called for Object " + this);
              return true;
          }

          /**
           * * Logout the user.
           */
          public boolean logout() throws LoginException
          {
              System.out.println("Logout method called for Object " + this);
              return true;
          }
      }

      ---------- END SOURCE ----------
      (Review ID: 138944)
      ======================================================================

            claisunw Charlie Lai (Inactive)
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: