/* **************************************************************************

  $Archive: /njcl_v2/src/com/novell/java/security/Authenticator.java $
  $Revision: 25 $
  $Modtime: 6/27/00 12:07p $

  Copyright (c) 1997-1998 Novell, Inc.  All Rights Reserved.

  THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL PROPRIETARY
  AND TRADE SECRET INFORMATION OF NOVELL, INC. ACCESS  TO  THIS  WORK IS
  RESTRICTED TO (I) NOVELL, INC.  EMPLOYEES WHO HAVE A NEED TO  KNOW HOW
  TO  PERFORM  TASKS WITHIN  THE SCOPE  OF  THEIR   ASSIGNMENTS AND (II)
  ENTITIES OTHER  THAN  NOVELL, INC.  WHO  HAVE ENTERED INTO APPROPRIATE
  LICENSE   AGREEMENTS.  NO  PART  OF  THIS WORK MAY BE USED, PRACTICED,
  PERFORMED COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED,  RECAST, TRANSFORMED
  OR ADAPTED  WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC.  ANY USE
  OR EXPLOITATION  OF  THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT THE
  PERPETRATOR  TO CRIMINAL AND CIVIL LIABILITY.

****************************************************************************/

package com.novell.java.security;

import java.util.*;

/**
 * Manages the authentication process for identities within a JVM. The
 * Authenticator achieves application authentication by prompting for
 * user credentials when an authentication request is issued. The
 * Authenticator uses the underlying requestor to perform the actual
 * authentication.
 * 
 * <p>
 * NOTE: The APIs required for the development of authentication protocols 
 * and storage of long-term authentication secrets are not part of the public 
 * release at this time, however, they may be made public in a future release.
 *
 * @see Identity
 * @see IdentityScope
 * @see com.novell.service.security.BinderyIdentity
 * @see com.novell.service.security.BinderyIdentityScope
 * @see com.novell.service.security.NdsIdentity
 * @see com.novell.service.security.NdsIdentityScope
 */
public final class Authenticator
{
   /**
    * Contains the state information of the Authenticator.
    */
   private static Vault vault;

   /**
    * Initialize the authenticator and login the
    * identities defined in the property file.
    */
   static
   {
      vault = new Vault();

      Identity identities[] = vault.getConfiguredIdentities();
      for(int i=0; i<identities.length;i++)
      {
         if(!(identities[i] instanceof IdentityScope))
            login(identities[i]);
      }
   } // static constructor

   /**
    * Default constructor made private to insure this is a static class.
    */
   private Authenticator (){}

   /**
    * Performs a login/logout of the Identity to its scope.
    *
    * @param identity            The Identity object to be logged in.
    * @exception LoginException  When an error occurs.
    */
   public static void login (
         Identity identity)
      throws LoginException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (identity);

      for (int i = 0; i < protocols.length; i++)
         protocols[i].login (identity);
   } // login ()

   /**
    * Modifies existing authentication login secrets or tokens for an
    * Identity object.
    *
    * <p>For password systems, this means changing a user password.
    * </p>
    *
    * @param identity            The Identity whose login tokens are to be
    *                            modified.
    * @exception ModifyTokensException When an error occurs.
    */
   public static void modifyTokens (
         Identity identity)
      throws ModifyTokensException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (identity);

      for (int i = 0; i < protocols.length; i++)
         protocols[i].modifyTokens (identity);
   } // modifyTokens ()

   /**
    * Creates new authentication login secrets or tokens for an Identity
    * object.
    *
    * <p>Typically, administrators use this method to initialize a user
    * object with some secret. For password systems, this means creating a
    * new user password.
    * </p>
    *
    * @param identity The Identity object whose login tokens are to
    *                 be created.
    * @exception ModifyTokensException When an error occurs.
    *
    * @deprecated This API should not be used, and may not work on some
    * platforms. It has been replaced with createTokens(Identity admin,
    * Identity user)
    * 
    */
   public static void createTokens (
         Identity identity)
      throws CreateTokensException
   {
   		// The semantics of this deprecated API is to use the rights of the user whose
   		// tokens are to be created.
   		createTokens( identity, identity);
   } // createTokens ()

   /**
    * Creates new authentication login secrets or tokens for an Identity
    * object.
    *
    * <p>Typically, administrators use this method to initialize a user
    * object with some secret. For password systems, this means creating a
    * new user password.
    * </p>
    *
    * @param admin The Identity object (typically, one with admin rights)
    *              whose permissions are to be used for creating user tokens.
    * @param user  The Identity object whose login tokens are to
    *                            be created.
    * @exception CreateTokensException When an error occurs.
    */
   public static void createTokens (
         Identity admin,
         Identity user)
      throws CreateTokensException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (user);

      for (int i = 0; i < protocols.length; i++)
         protocols[i].createTokens (admin, user);
   } // createTokens ()

   /**
    * Verifies existing authentication login secrets or tokens for an
    * Identity object.
    *
    * <p>For password systems, this means verifying a user password.
    * </p>
    *
    * @param identity            The Identity whose login tokens are to be
    *                            verified.
    * @exception VerifyTokensException When an error occurs.
    */
   public static synchronized void verifyTokens (
         Identity identity)
      throws VerifyTokensException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (identity);

      for (int i = 0; i < protocols.length; i++)
         protocols[i].verifyTokens (identity);
   } // verifyTokens ()


   /**
    * Logs out (destroys) the specified Identity object and the
    * associated short-term credentials from its identity scope.
    *
    * @param identity            The Identity object to be logged out.
    * @exception LogoutException When an error occurs.
    */
   public static void logout (
         Identity identity)
      throws LogoutException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (identity);

      for (int i = 0; i < protocols.length; i++)
         protocols[i].logout (identity);
   } // logout ()

   /**
    * Returns a list of currently authenticated Identity objects.
    *
    * @return                    The array of currently authenticated
    *                            Identity objects.
    * @exception GetIdentitiesException When an error occurs.
    */
   public static Identity[] getIdentities ()
      throws GetIdentitiesException
   {
      Identity identity = null;

      Identity ids[] = vault.getConfiguredIdentities ();
      if (ids != null && ids.length != 0)
         identity = ids[0];
      else
         throw new GetIdentitiesException (I2L.getString(XMsg.NO_DEFAULT_IDENTITY_EXISTS));
      try
      {
         return getIdentities ((IdentityScope) identity);
      }
      catch (ClassCastException x)
      {
         throw new GetIdentitiesException (I2L.getString(XMsg.NO_DEFAULT_SCOPE_EXISTS),x);
      }
   } // getIdentities ()

   /**
    * Returns a list of currently authenticated Identity objects
    * within the specified scope.
    *
    * @param scope               The IdentityScope to be searched for
    *                            authenticated Identity objects.
    * @return                    The array of Identity objects currently
    *                            authenticated.
    * @exception GetIdentitiesException When an error occurs.
    */
   public static Identity[] getIdentities (
         IdentityScope scope)
      throws GetIdentitiesException
   {
      AuthenticatorProtocol protocols[] = vault.getProtocols (scope);

      java.util.Vector v = new java.util.Vector ();
      for (int i = 0; i < protocols.length; i++)
      {
         Identity id[] = protocols[i].getIdentities (scope);
         for (int j = 0; j < id.length; j++)
            v.addElement (id[j]);
      }

      Identity identities[] = new Identity [v.size ()];

      v.copyInto (identities);

      return identities;
   } // getIdentities ()

   /**
    * Returns the name of the identity that was last successfully acted on by the Authenticator (e.g. login, logout, password change, etc.) by the current thread.
    * This is useful for cases where the user changes the information in an Authenticator dialog.
    */
   public static String getLastUsername() {
      return (String) LastUsernames.get(Thread.currentThread());
   }

   /**
    * Returns the domain of the identity that was last successfully acted on by the Authenticator (e.g. login, logout, password change, etc.) by the current thread.
    * This is useful for cases where the user changes the information in an Authenticator dialog.
    */
   public static String getLastUserDomain() {
      return (String) LastDomains.get(Thread.currentThread());
   }

    /**
     * @internal
     */
    public static void putLast(String Name, String Domain, Thread Thread) {

        if (Thread == null)
            Thread = Thread.currentThread();

        if (Name == null)
            LastUsernames.remove(Thread);
        else
            LastUsernames.put(Thread, Name);

        if (Domain == null)
            LastDomains.remove(Thread);
        else
            LastDomains.put(Thread, Domain);
            
        synchronized (LastUsernames) {
            
            Vector v = new Vector();
            
            for (Enumeration e = LastUsernames.keys(); e.hasMoreElements(); ) {
                Thread t = (Thread) e.nextElement();
                if (!t.isAlive())
                    v.addElement(t);
            }

            for (Enumeration e = LastDomains.keys(); e.hasMoreElements(); ) {
                Thread t = (Thread) e.nextElement();
                if (!t.isAlive())
                    v.addElement(t);
            }
                
            for (int i = 0; i < v.size(); i++) {
                LastUsernames.remove(v.elementAt(i));
                LastDomains.remove(v.elementAt(i));
            }
        }
    }
    
    static private Hashtable LastUsernames = new Hashtable(23);
    static private Hashtable LastDomains = new Hashtable(23);
    
} // class Authenticator
