package examples.security.acl;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.StringTokenizer;
import javax.naming.Context;
import weblogic.jndi.Environment;
import weblogic.security.PEMInputStream;
import weblogic.security.X509;
import weblogic.security.acl.DefaultUserInfoImpl;


/** 
 * This simple client connects as a specific user and attempts an RMI
 * invocation. Access to the invocation will be granted or denied
 * depending on the configured ACLs. <p>
 *
 * This differs from the Client example in two ways:
 * <ul>
 *
 * <li>It uses Environment to establish the initial JNDI context
 * instead of InitialContext and a Hashtable.
 *
 * <li>It attempts to perform two-way SSL authentication, if a client
 * private key and certificates are provided.
 *
 * </ul>
 *
 * If you want to test two-way SSL authentication, you can use the
 * <code>demokey.pem</code> and <code>democert.pem</code> files
 * provided in your installation as your client key and certificate.
 * Don't forget to configure the server to require two-way SSL
 * authentication; it should use the <code>ca.pem</code> file (also
 * in your installation) as the Certification Authority to check for
 * when clients connect.
 *
 * @author Copyright (c) 2000 by BEA Systems, Inc. All Rights Reserved.
 * @see examples.security.acl.Client
 */
public class AltClient
{
  /** 
   * The main entry point.  The summary is that we check our
   * parameters, look up <tt>frobtarget</tt>, call <tt>frob</tt> on
   * it, and report on whether it succeeded.
   */
  public static void main(String[] args)
  {
    Context ctx = null;
    
    if (args.length < 1)
    {
      usage();
    }

    String url = args[0];
    
    try
    {
      Environment env = new Environment();

      env.setProviderUrl(url);

      // If we've been given an explicit username and password, use
      // them.  Otherwise, the JNDI connection will attempt to default
      // to guest/guest.

      String user = null;
      
      for (int arg = 1; arg < args.length; arg++)
      {
	if (args[arg].equals("-user") && arg + 1 < args.length)
	{
	  env.setSecurityPrincipal(user = args[++arg]);
	}
	else if (args[arg].equals("-pass") && arg + 1 < args.length)
	{
	  env.setSecurityCredentials(args[++arg]);
	}
	else if (args[arg].equals("-sslCert") && arg + 1 < args.length)
	{
	  // If we've been asked to make a secure T3 connection and we
	  // have enough arguments, we populate the SSL client
	  // certificate so that we can attempt two-way SSL authentication.

	  // In order to do this, we must make an array of at least two
	  // InputStream objects; the first is the client's private key,
	  // and the rest are the certificate chain, starting with the
	  // client's certificate (which must be present) and ending with
	  // the root CA's certificate.

	  InputStream[] certs = readCerts(args[++arg]);

	  if (url.startsWith("t3s") || url.startsWith("https"))
	  {
	    env.setSSLClientCertificate(certs);
	  } else {
	    fatal("the URL doesn't specify use of SSL");
	  }
	}
	else if (args[arg].equals("-cert") && arg + 1 < args.length)
	{
	  if (user == null)
	  {
	    fatal("user name must be specified before certificate chain");
	  }
	  
	  InputStream[] certs = readCerts(args[++arg]);
	  X509[] x509 = new X509[certs.length];

	  for (int i = 0; i < certs.length; i++)
	  {
	    x509[i] = new X509(certs[i]);
	  }

	  env.setSecurityCredentials(new DefaultUserInfoImpl(user, x509));
	} else {
	  usage();
	}
      }

      ctx = env.getInitialContext();

      Frobable f = (Frobable) ctx.lookup("frobtarget");
      f.frob();
      System.out.println("Frobbed successfully");
    }
    catch (Throwable t)
    {
      t.printStackTrace();
      System.out.println("Failed to frob");
    }
    finally
    {
      try
      {
	if (ctx != null)
	{
	  ctx.close();
	}
      }
      catch (Exception e)
      {
        // Deal with any failures
      }
    }
  }


  private static final String pathSep =
    (String) System.getProperty("path.separator", ":");

  
  private static InputStream[] readCerts(String files)
    throws IOException
  {
    StringTokenizer toks = new StringTokenizer(files, pathSep);
    InputStream[] streams = new InputStream[toks.countTokens()];

    for (int i = 0; i < streams.length; i++)
    {
      String file = toks.nextToken();

      InputStream is = new FileInputStream(file);

      if (file.toLowerCase().endsWith(".pem"))
      {
	is = new PEMInputStream(is);
      }

      streams[i] = is;
    }
    
    return streams;
  }
  
  private static void fatal(String msg)
  {
    System.err.println("Error: " + msg);
    System.exit(1);
  }

  
  private static void usage()
  {
    System.err.println("Usage:\tjava examples.security.acl.AltClient " +
		       "URL [-user username]");
    System.err.println("\t[-pass password] [-cert cert1" + pathSep + "cert2" +
		       pathSep + "...] [-sslCert key" + pathSep + "cert1" +
		       pathSep + "...]");
    System.err.println("e.g.:\tjava examples.security.acl.AltClient " +
		       "t3s://localhost:7002 -user guest -pass guest");
    System.exit(1);
  }
}
