/***********************************************************************
 * 
 *  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>
 *
 ***********************************************************************/

//===[ Include files ]=====================================================

#include "internal.h"

//===[ Type definitions ]==================================================

//===[ Function prototypes ]===============================================

//===[ Global variables ]==================================================

// Debug Level
int   DebugLevel = 0;

//
// Initialization variables
//
static
bool  g_moduleInitialized = false;


//++=======================================================================
CasaStatus SSCS_CALL
ValidateAuthToken(
   IN       const char  *pServiceName,
   IN       const char  *pTokenBuf,
   IN       const int   tokenBufLen,
   INOUT    PrincipalIf **ppPrincipalIf)
//
// Arguments:  
//    pServiceName -
//       Pointer to NULL terminated string that contains the
//       name of the service targeted by the token.
//               
//    pTokenBuf -
//       Pointer to buffer that will receive the authentication
//       token. The length of this buffer is specified by the
//       pTokenBufLen parameter. Note that the the authentication
//       token will be in the form of a NULL terminated string.
//
//    tokenBufLen -
//       Length of the data contained within the buffer pointed
//       at by pTokenBuf.
//   
//    ppPrincipalIf -
//       Pointer to variable that will receive a pointer to a principal
//       interface with information about the authenticated entity.
//       IMPORTANT NOTE: The caller is responsible for releasing the
//       interface after it is done with it to avoid a resource leak.
//   
// Returns:
//    Casa status.
//                           
// Description:
//    Validates authentication token.
//
// L2
//=======================================================================--
{
   CasaStatus        retStatus;
   char              *pDecodedTokenBuf;
   int               decodedTokenBufLen;
   PrincipalIf       *pPrincipalIf;

   DbgTrace(1, "-ValidateAuthToken- Start\n", 0);

   // Validate input parameters
   if (pServiceName == NULL
       || pTokenBuf == NULL
       || tokenBufLen == 0
       || ppPrincipalIf == NULL)
   {
      DbgTrace(0, "-ValidateAuthToken- Invalid input parameter\n", 0);

      retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
                                  CASA_FACILITY_AUTHTOKEN,
                                  CASA_STATUS_INVALID_PARAMETER);
      goto exit;
   }

   // Make sure that the module has been initialized
   if (g_moduleInitialized == false)
   {
      // The module has not been initialized, synchronize access thought this section
      // to avoid having two threads performing initialization.
      AcquireModuleMutex;

      // Assume success
      retStatus = CASA_STATUS_SUCCESS;

      // Check again in case another thread pre-empted us.
      if (g_moduleInitialized == false)
      {
         // Initialize the ConfigIf complex
         retStatus = ConfigIfInit();
         if (CASA_SUCCESS(retStatus))
         {
            // Initialize the PrincipalIf complex
            retStatus = PrincipalIfInit();
            if (CASA_SUCCESS(retStatus))
            {
               // Initialize the IdenToken complex
               retStatus = IdenTokenInit();
               if (CASA_SUCCESS(retStatus))
               {
                  // Success
                  g_moduleInitialized = true;
               }
               else
               {
                  PrincipalIfUninit();
                  ConfigIfUninit();
               }
            }
            else
            {
               ConfigIfUninit();
            }
         }
      }

      // Stop synchronization
      ReleaseModuleMutex;

      // Exit if we failed
      if (g_moduleInitialized == false)
         goto exit;
   }

   // First decode the token string
   retStatus = DecodeData(pTokenBuf,
                          tokenBufLen,
                          (void**) &pDecodedTokenBuf,
                          &decodedTokenBufLen);
   if (CASA_SUCCESS(retStatus))
   {
      AuthToken *pAuthToken;

      // Token was decoded successfully, now create an authentication token object with it.
      retStatus = CreateAuthToken(pDecodedTokenBuf, decodedTokenBufLen, &pAuthToken);
      if (CASA_SUCCESS(retStatus))
      {
         // Now check the validity of the token
         retStatus = CheckAuthToken(pAuthToken, pServiceName);
         if (CASA_SUCCESS(retStatus))
         {
            IdenTokenProviderIf  *pIdenTokenProviderIf;

            // The token was validated, now
            // Obtain Identity Token Provider interface
            retStatus = GetIdenTokenProviderInterface(pAuthToken->pIdenTokenType,
                                                      &pIdenTokenProviderIf);
            if (CASA_SUCCESS(retStatus))
            {
               IdenTokenIf *pIdenTokenIf;

               // Use the Identity Token Provider to get an Identity Token Interface instance
               retStatus = pIdenTokenProviderIf->getIdentityTokenIf(pIdenTokenProviderIf,
                                                                    pAuthToken->pIdenToken,
                                                                    pAuthToken->idenTokenLen,
                                                                    &pIdenTokenIf);
               if (CASA_SUCCESS(retStatus))
               {
                  // Now create a principal interface instance with the identity information present in
                  // the identity token.
                  retStatus = GetPrincipalInterface(pIdenTokenIf, &pPrincipalIf);
                  if (CASA_SUCCESS(retStatus))
                  {
                     // Success, return the principal interface to the caller.
                     *ppPrincipalIf = pPrincipalIf;
                  }
                  else
                  {
                     DbgTrace(0, "-ValidateAuthToken- Failed to instantiate principal interface\n", 0);
                  }

                  // Release identity token interface
                  pIdenTokenIf->releaseReference(pIdenTokenIf);
               }
               else
               {
                  DbgTrace(0, "-ValidateAuthToken- Failed to instantiate identity token\n", 0);
               }

               // Release identity token provider interface
               pIdenTokenProviderIf->releaseReference(pIdenTokenProviderIf);
            }
            else
            {
               DbgTrace(0, "-ValidateAuthToken- Failed to obtain identity token provider interface\n", 0);
            }
         }

         // Free the AuthToken object
         RelAuthToken(pAuthToken);
      }
      else
      {
         DbgTrace(0, "-ValidateAuthToken- Failed to create authentication token object\n", 0);
      }

      // Free the decoded token buffer
      free(pDecodedTokenBuf);
   }
   else
   {
      DbgTrace(0, "-ValidateAuthToken- Token decode failure\n", 0);
   }

exit:

   DbgTrace(1, "-ValidateAuthToken- End, retStatus = %08X\n", retStatus);

   return retStatus;
}


//++=======================================================================
//++=======================================================================
//++=======================================================================