Pages

Tuesday, February 5, 2013

Create a Pharos Uniprint Logon Script to resolve ADLDAPLogon.exe Short Falls

I got a few calls from users complaining about our Pharos Clients getting "The username and password could not be authenticated against any servers" error Message. Now while a lot of users where getting this error it was only a small percentage of the over all print jobs. After digging around and putting a call into Pharos Support I noticed that this wasn't just a recent start of errors but rather common. If you want to check for it you can search your alerts or table or use Pharos administrator to and a Custom filter on the alerts.

SELECT        TOP (100) PERCENT message, username, client, time
FROM            dbo.alerts
WHERE        (message LIKE '%The username and password could not be authenticated against any servers%')
ORDER BY time DESC

Cause


Turns out the ADLDAPLogon.exe basically just don't do much checking as to why a username failed. From what testing I did I turns out the following all return the same error.
  • If the username appended with any  SMTP Address of @domain.com to the username
  • If the username is incorrect in that no account in Pharos with that name exists.
  • if the username doesn't match AD
  • .... I'm sure there are others.

Solution 

As such I talking with the Pharos Support Rep they could write a Plug-in that called ADLDAPLogon.exe but that it would be a charged Service on their part. As such I wrote my own this morning and figured I'd share.

The following Script will do the following check and then check if the username and password are correct.

  • Confirm that the Username exists in the Pharos Database
  • That the PlugIn.UserName is not empty
  • That the PlugIn.Password is not empty
  • Remove any @domain.com from the username
This script does require that ADLDAPLogon.exe is in place and configured correctly.

Then Create the Script in under system. Go to your bank, and change the Logon event from useing ADLDAPLogon.exe to use the newly created Logon Script instead. Do a change control and you done.




Good luck and feel free to  use and modify this script to fit your needs. 


//  PlugIn Script: Logon - NKU ADLDAPLogon.exe
// 
//  Billing PlugIn to allow stripping the username of @domain.com before passing to adldaplogon.exe 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  Project:        Pharos 8.3
//  Design:         NKU
//  Date:           5-February-2013
//  Where:          Northern Kentucky University 
//  Who:            Chris Towles written from scratch
//  --------------------------------------------------------------
//  Modifications:
//    02-05-13 Chris Towles : Created to strip the username of @domain.com before passing to adldaplogon.exe 
//   
//
// Description:
//    This Logon Script allows a full email address to be used as the username. It strips the '@' and everything that follows then calls
//
// Requirements:
//    1. adldaplogon be installed and configured
//        C:\Program Files (x86)\Pharos\Bin>adldaplogon.exe --list
//
//  
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// import namespaces
import "DB";
import "Win32";
import "String";  
import "IO";

import "User";

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constants (customizable)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//#region Constants

//...string
new sScriptName          = "Logon - NKU ADLDAPLogon.exe";
new sLogPrefix           = "[" + sScriptName + "] -> ";

IO.PrintLine("Solution: " + sScriptName);



// While the path can be hard-coded here as a string, this tends to break in heterogeneous
// environments, e.g. mixed 32- and 64-bit servers.  If possible, install plug-ins relative
// to the Pharos installation folder and query the registry for the starting point:
new sPharosPath = Win32.RegQueryValue("SOFTWARE\\Pharos\\Installed Components", "Path");

// Win32.SearchPath will return the shortened path and file names.
// Be sure to specify the remainder of the path relative to the Pharos folder.
new sADLDAPLogonPath            = Win32.SearchPath(sPharosPath + "\\Bin\\adldaplogon.exe");

//new sADLDAPLogonPath = "C:\\Program Files (x86)\\Pharos\\Bin\\adldaplogon.exe";

new eErrorInvalidUserNamePassword      = "Invalid username or password";
new eErrorInvalidUserName              = "The given username doesn't exist. Please be sure to enter your AD username.";
new eErrorPlugInResultsNotValid        = "Results from Logon plug-in are not valid. Please contact the information desk.";
new eErrorUsernameIsEmpty              = "You must enter a Username.";
new eErrorPasswordIsEmpty              = "You must enter a password.";


// - Logon Plug-in timeout (milliseconds)
new iCmdTimeout = 30000;


//#region Variables
//...boolean
new bResult = false;
new bIsPharosAccountAvailable  = false;


//...integer
new iPos;
new iUserID;


//...string
new UserName = PlugIn.UserName;
new sResultsFile;
new sADLDAPLogonCommand = "";
new sADLDAPLogonResult = "";
new sADLDAPLogonError = "";
new sResult = "";


//---------------------------------------------------------------------------------------
// Functions code
//---------------------------------------------------------------------------------------

function IsAccountAvailable(name)
{
    try
    {
        IO.PrintLine(sLogPrefix + "Get user by logon id.");
        User.GetUserByLogon(name);
        return true;
    }
    catch
    {
        IO.PrintLine(sLogPrefix + "Failed to get user by logon id. Get user by card id.");
        try
        {
            User.GetUserByCardID(name);
            return true;
        }
        catch
        {
            IO.PrintLine(sLogPrefix + "Failed to get user by logon id or card id.");
            return false;

        }
    }

}


//---------------------------------------------------------------------------------------
// PlugIn code
//---------------------------------------------------------------------------------------

//---------------------------------------------------
// Default the script to fail. Set default error
// message to Invalid Username/Password. 
//---------------------------------------------------
PlugIn.Result = false;
PlugIn.Error = eErrorInvalidUserNamePassword;


//---------------------------------------------------------------------------------------
// Clean Up the Username and strip the domain name off of it
//---------------------------------------------------------------------------------------


if (String.IsEmpty(PlugIn.UserName) )
{
    IO.PrintLine(sLogPrefix + " User entered an empty username. Fail the logon.");
    PlugIn.Result = false;
    PlugIn.Error = eErrorUsernameIsEmpty;
}
else { //strip the @Domain.com from the account. 
    
    iPos = String.Find(UserName, "@");
    if (iPos != -1)
    {
        String.Left(UserName, iPos);
    }
    iPos = 0;

    
    
    bIsPharosAccountAvailable = IsAccountAvailable(UserName);

    if (bIsPharosAccountAvailable == false)
    {
        IO.PrintLine(sLogPrefix + "User Account doesn't exist.");
        PlugIn.Result = false;
        PlugIn.Error = eErrorInvalidUserName + " : " + UserName;
    }   
    else 
    {
    
        //From now on in the script user "UserName" instead of PlugIn.UserName

        //---------------------------------------------------
        // Check if the user must enter a password (if
        // enabled.
        //---------------------------------------------------
        if (String.IsEmpty(PlugIn.Password) )
        {
            IO.PrintLine(sLogPrefix + "User entered an empty password. Fail the logon.");
            PlugIn.Result = false;
            PlugIn.Error = eErrorPasswordIsEmpty;
        }
        else
        {
            //---------------------------------------------------
            //Verify the users Password
            //---------------------------------------------------

            //adldaplogon.exe out.txt user  
      
            sResultsFile = Win32.GetTempFileName();
            sADLDAPLogonCommand = sADLDAPLogonPath + " " +
                        sResultsFile + 
                        " user " +
                        UserName + " " +
                        PlugIn.Password;
        
            //Write to the Pharos Print Server log Note this would have the username and password
            //IO.PrintLine ( ">sADLDAPLogonCommand :: " + sADLDAPLogonCommand);
        
            Win32.ExecProcess(sADLDAPLogonCommand, iCmdTimeout);
        
            bResult = IO.LoadFile(sADLDAPLogonResult, sResultsFile);
        
            //Write to the Pharos Print Server log
            IO.PrintLine ( "> Logon bResult :: " + bResult);
            IO.PrintLine ( "> Logon sADLDAPLogonResult :: " + sADLDAPLogonResult);

            //Clean Up and delete the Temp Output file            
            IO.DeleteFile(sResultsFile);

            if (bResult)
            {
              //get first line from sADLDAPLogonResult
              sResult = sADLDAPLogonResult;
              iPos = String.Find(sADLDAPLogonResult, "\r\n");
              if (iPos != -1)
              {
                  String.Left(sResult, iPos);
                  String.UpperCase(sResult);
                  String.Delete(sADLDAPLogonResult, 0, String.Length(sResult));
                  String.TrimLeft(sADLDAPLogonResult);
              }

              if (sResult == "FAIL")
              {
                     //ADLDAPLogon Failed
                  iPos = String.Find(sADLDAPLogonResult, "\r\n");
                  sADLDAPLogonError = sADLDAPLogonResult;
                  if (iPos != -1)
                     {
                    String.Left(sADLDAPLogonError, iPos);
                  }

                     IO.PrintLine(sLogPrefix + "ADLDAPLogon.exe returned a FAIL : " + sADLDAPLogonError);
                    
                     PlugIn.Result = false;
                     PlugIn.Error = eErrorInvalidUserNamePassword + " : " + UserName;
                     IO.PrintLine(sLogPrefix + "Returning the user this error : " + PlugIn.Error );
                 }    
              else 
                 {
                    if (sResult == "OK")
                 {
                        // Logon was successful.
                  IO.PrintLine(sLogPrefix + "ADLDAPLogon.exe login was successful for user '" + UserName + "'");
                        PlugIn.Result = true;
                    }
                   else
                    {
               //...Unkown Error 
                        IO.PrintLine(sLogPrefix + "ADLDAPLogon.exe Result was not Valid");
                    PlugIn.Error = eErrorPlugInResultsNotValid;
                    PlugIn.Result = false;
                    }
                 }
              } //end of  if (bResult)
           } //end of password check
        }// Check if Pharos Account exists
    }//End of Username Check

2 comments:

  1. Good work - looks like you've done some solid work here! We had similar issues, although I tracked that down to Pharos not passing the parameters to adldaplogon.exe in the correct order. Our fix was to create a batch file adldaplogon.cmd that called adldaplogon.exe with the correct parameter order.

    So the batch file simply contains:
    ====
    "%ProgramFiles%\Pharos\bin\adldaplogon.exe" %1 User %2 %3
    ====

    And the Logon hook updated to use this batch file instead of adldaplogon.exe directly.

    Been like this for years AFAIK. Crazy that it's still required!

    Just did a quick Google - looks like we're not the only ones to strike this: http://rcmtech.wordpress.com/2012/08/15/pharos-uniprint-8-2-adldap-authentication-failure/

    Just thought this would be useful info to have here as an alternative method of getting the adldaplogon stuff working.

    ReplyDelete
  2. Hi Chris - I realize the age of this post, so I'm hoping this still finds its way to you. I am curious if you know if the error verbiage "The username and password could not be authenticated against any servers" is Windows-side or Pharos-side, and if the latter can it be changed so that Pharos Users could receive a more tailored message, such as "your username or password is incorrect"? I'm thinking that's what a custom logon script could accomplish? Thanks!

    ReplyDelete

Please leave a comment; someone, anyone!