/***********************************************************************
 * 
 *  Copyright (C) 2006 Novell, Inc. All Rights Reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; version 2.1
 *  of the License.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, Novell, Inc.
 * 
 *  To contact Novell about this file by physical or electronic mail, 
 *  you may find current contact information at www.novell.com.
 * 
 *  Author: Juan Carlos Luciani <jluciani@novell.com>
 *  
 ***********************************************************************/

package com.novell.casa.jaas.sample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Set;

import javax.naming.NamingEnumeration;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import com.novell.casa.jaas.CasaPrincipal;


/*
 * This is a sample application which demonstrates the use of
 * JAAS and Casa to authenticate a connection.
 */
public final class SampleApp
{
   /**
    * @param args
    */
   public static void main(String[] args)
   {
      Socket sock = null;
      ServerSocket listenSock = null;
      
      try
      {
         // Create a socket to listen for connections
         int port = 4444;
         int queueLen = 6;
         System.out.println("Listen port = " + port);
         listenSock = new ServerSocket(port, queueLen);

         // Service connections
         while (true)
         {
            BufferedReader in = null;
            try
            {
               // Wait for the next connection
               System.out.println("Waiting for connection");
               sock = listenSock.accept();
               System.out.println();
               System.out.println("********Connection received*********");
               
               // Get socket I/O streams
               in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
               //PrintStream out = new PrintStream(sock.getOutputStream());
               
               // Get the authentication token from the client
               String authToken = in.readLine();
               //System.out.println("Token received from client, length = " + authToken.length());
               
               // Authenticate the token and print out the information available to our service
               // about the authenticated identity.
               LoginContext lc = new LoginContext("testService", new SampleAppCallbackHandler(authToken));
               try
               {
                  System.out.println("Authenticating the user");
                  lc.login();
                  
                  System.out.println("   Authentication succeeded");
                  
                  // Now get the subject associated with the context
                  Subject subject = lc.getSubject();
                  
                  // Now get the CasaPrincipals that represent the authenticated
                  // identity or identities.
                  Set principalSet = subject.getPrincipals(CasaPrincipal.class);
                  //System.out.println("The number of CasaPrincipals is: " + principalSet.size());
                  Iterator principalIter = principalSet.iterator();
                  System.out.println();
                  System.out.println("Authenticated Identity Information");
                  System.out.println();
                  while (principalIter.hasNext())
                  {
                     CasaPrincipal principal = (CasaPrincipal) principalIter.next();
                     
                     // Print out information about the principal
                     System.out.println("   Source of the identity information: " + principal.getIdentStoreUrl());
                     System.out.println("   Realm name associated with identity source: " + principal.getRealm());
                     System.out.println("   Principal name (unique within identity source realm): " + principal.getName());
                     System.out.println();
                     System.out.println("Authenticated Identity Attributes");
                     System.out.println();
                     javax.naming.directory.Attributes attrs = principal.getAttributes();
                     for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();)
                     {
                        javax.naming.directory.Attribute attr = (javax.naming.directory.Attribute) ae.next();
                        
                        NamingEnumeration enumeration = attr.getAll();
                        while (enumeration.hasMore())
                        {
                           System.out.print("  Attribute Name: " + attr.getID());
                           Object attrValue = enumeration.next();
                           if (attrValue instanceof byte[])
                           {
                              // The attribute value is binary data
                              StringBuffer buf = new StringBuffer();
                              char[] hex = "0123456789ABCDEF".toCharArray();
                              for (int i = 0; i < ((byte[]) attrValue).length; i++)
                              {
                                 buf.append(hex[(((byte[]) attrValue)[i] >> 4) & 0xF]);
                                 buf.append(hex[((byte[]) attrValue)[i] & 0xF]);
                              }
                              System.out.println(" :: Attribute Value: " + buf.toString());
                           }
                           else
                           {
                              // The attribute value is contained in a string
                              System.out.println(" :: Attribute Value: " + attrValue);
                           }
                        }
                     }
                  }
                  System.out.println();
               }
               catch (LoginException e)
               {
                  System.out.println("   Authentication failed, LoginException: " + e.getMessage());
               }
            }
            finally
            {
               if (sock != null)
               {
                  sock.close();
                  sock = null;
               }
               if (in != null)
                  in.close();
            }
         }
      }
      catch (IOException e)
      {
         System.out.println("IOException: " + e.getMessage());
      }
      catch (Exception e)
      {
         System.out.println("Exception: " + e.getMessage());
      }
      finally
      {
         try
         {
            if (sock != null)
            {
               sock.close();
            }
            if (listenSock != null)
            {
               listenSock.close();
            }
         }
         catch (Exception e)
         {
            System.out.println("Exception: " + e.getMessage());
         }
      }
   }
}
