authenticationservices/authenticationserver/test/tauthcliserv/step_client.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 17:00:08 +0300
branchRCL_3
changeset 95 641f389e9157
permissions -rw-r--r--
Revision: 201035 Kit: 201035

/*
* Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include <test/testexecutelog.h>
#include "tauthcliservstep.h"
#include "authserver/aspubsubdefs.h"
#include <e32property.h>
#include <authserver/authpatchdata.h>
#include <u32hal.h>
#include <e32svr.h>
 
using namespace AuthServer;

class CAuthActive : CActive
    {
public:
    CAuthActive(RAuthClient& aClient, CIdentity*& aResult, CTStepClient* aStep,
				TBool aStop = ETrue) : 
         CActive(EPriorityNormal),
         iFirstTime(true),
         iClient(aClient), 
         iResult(aResult), 
         iStep(aStep),
		 iStop(aStop)
	    {
        CActiveScheduler::Add(this);
        }
	
    void doAuthenticate(TPluginId aPlugin, TTimeIntervalSeconds aTime )
        {
		iPlugin = aPlugin;
        SetActive();		
		TRequestStatus* status = &iStatus;		    
		User::RequestComplete(status, KErrNone);
		iFirstTime = ETrue;
		iTime = aTime;
        }
	
        void DoCancel() 
        {
        }
        void RunL() 
        {
		static TBool client = ETrue;
		static TBool withString = ETrue;
		client = !client;
        if (iFirstTime)
            {
			// inactive | plugin id
            iAe = AuthExpr(0x10274106) | AuthExpr(iPlugin);
			User::LeaveIfNull(iAe);
			SetActive();
            iStatus = KRequestPending;
            iClient.AuthenticateL(*iAe, iTime, client, withString,
								  iResult, iStatus);
            iFirstTime = false;
            }
        else
            {
			if (iStop)
				{
				CActiveScheduler::Stop();
				}
            delete iAe;
			}
		iErr =  iStatus.Int();
		}
    TBool iFirstTime;
    RAuthClient& iClient;
    CIdentity*& iResult;
    CTStepClient* iStep;
    CAuthExpression* iAe;
    TPluginId        iPlugin;
	TTimeIntervalSeconds iTime;
	TInt iErr;
	TBool iStop;
    };



const TPluginId KIdentity1Id = 0xE0494423;
_LIT(KIdentity1Desc, "identity-1-desc");
const TPluginId KIdentity2Id = 0xE0494443;
_LIT(KIdentity2Desc, "identity-2-desc");
const TPluginId KIdentity3Id = 0xE0494453;



CTStepClient::CTStepClient()
/**
	Record this test step's name.
 */
	{
 	SetTestStepName(KTStepClient);
	}


void CTStepClient::TestIdentitiesL()
/**
	Test can retrieve correct identity arrays and
	descritptinos from auth db.
 */
	{
	__UHEAP_MARK;
	RemoveExistingDbL();
	
	RArray<TIdentityId> ids;
	

	// one identities (first start adds one)
	GetIdentitiesLC(ids);
	TESTL(ids.Count() == 1);
	CleanupStack::PopAndDestroy(&ids);

	
	// two identity
	AddIdentityL(KIdentity1Id, KIdentity1Desc);
	GetIdentitiesLC(ids);
	TESTL(ids.Count() == 2);
	TESTL(ids[0] == KIdentity1Id || ids[1] == KIdentity1Id);
	CleanupStack::PopAndDestroy(&ids);
	TestIdentityL(KIdentity1Id, KIdentity1Desc);
	
	
	// three identities
	AddIdentityL(KIdentity2Id, KIdentity2Desc);
	GetIdentitiesLC(ids);
	TESTL(ids.Count() == 3);
	TESTL(	ids.Find(KIdentity1Id) >= 0 && 
	        ids.Find(KIdentity2Id) >= 0);
	CleanupStack::PopAndDestroy(&ids);
	TestIdentityL(KIdentity1Id, KIdentity1Desc);
	TestIdentityL(KIdentity2Id, KIdentity2Desc);

	// test fail to get description for non-existent identity
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);
	
	
	TRAPD(r, ac.IdentityStringL(KIdentity3Id));
	TESTL(r == KErrAuthServIdentityNotFound);

	// check id and string retrieval
	RIdAndStringArray idWithString;
	ac.IdentitiesWithStringL(idWithString);
	CleanupClosePushL(idWithString);
	
    for (TInt i = 0 ; i < idWithString.Count() ; ++i)
	    {
	    TestIdentityL(idWithString[i]->Id(), *idWithString[i]->String());
		INFO_PRINTF3(_L("0x%x - %S"), idWithString[i]->Id(), idWithString[i]->String()); 
	    }

	CleanupStack::PopAndDestroy(2,&ac);
	
	__UHEAP_MARKEND;
	}


void CTStepClient::GetIdentitiesLC(RArray<TIdentityId>& aIds)
/**
	Populate the supplied array with the currently available
	identities, as returned by the server.
	
	@param	aIds			Array to populate.  Any existing entries
							are removed when this function is called.
							On success, the array is placed on the
							cleanup stack.
 */
	{
	aIds.Reset();
	CleanupClosePushL(aIds);
	
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);
	ac.IdentitiesL(aIds);	// clears array on failure?
	CleanupStack::PopAndDestroy(&ac);
	}


void CTStepClient::AddIdentityL(TIdentityId aIdentityId, const TDesC& aDesc)
/**
	Add the described identity directly to the database.
	
	This function does not use the authentication manager APIs.
 */
	{
	WaitForServerToReleaseDb();
	CAuthDb2* db = CAuthDb2::NewL(iFs);
	CleanupStack::PushL(db);
	db->AddIdentityL(aIdentityId, aDesc);
	CleanupStack::PopAndDestroy(db);
	}


void CTStepClient::TestIdentityL(TIdentityId aIdentityId, const TDesC& aExpDesc)
/**
	Test the supplied identity has the supplied description,
	as read via the RAuthClient API.
	
	@param	aIdentityId		Identity to retrieve description for.
	@param	aExpDesc		The expected description.
 */
	{
	RAuthClient ac;
	CleanupClosePushL(ac);
	User::LeaveIfError(ac.Connect());
	HBufC* desc = ac.IdentityStringL(aIdentityId);
	CleanupStack::PushL(desc);
	TESTL(*desc == aExpDesc);
	CleanupStack::PopAndDestroy(2, &ac);
	}


/**
	TestClientPluginListsL poulates this with a description for
	every plugin that can be seen with ECOM.
 */
static RCPointerArray<CPluginDesc> allPlugins;

/**
	Total number of plugins on the device.  Should be equal to
	allPlugins.Count().
 */
static TInt totalCount;

/**
	Maximum number of plugins which can are expected.  This is
	an arbitrary value which is used to size an array.  It can be
	changed if required.
 */
const TInt KMaxSeenCount = 17;

/**
	This array stores how many times each plugin from allPlugins
	has been seen.  It is set by SetSeenCountsL.
 */
static TFixedArray<TInt, KMaxSeenCount> seenCounts;


void CTStepClient::GetDescriptionsFromEComL(RPointerArray<CPluginDesc>& aDescs)
/**
	Populate the supplied array with plugin descriptions generated
	from the available ECOM plugins.  The array can then be used to
	check the results from the server.
 */
	{
	WaitForServerToReleaseDb();
	
	CAuthDb2* db = CAuthDb2::NewL(iFs);
	CleanupStack::PushL(db);
	
	// typedef RPointerArray<CImplementationInformation> RImplInfoPtrArray;
	RCPointerArray<CImplementationInformation> implInfo;
	REComSession::ListImplementationsL(KCAuthPluginInterfaceUid, implInfo);
	CleanupClosePushL(implInfo);
	
	TInt implCount = implInfo.Count();
	TInt err = 0;
	for (TInt i = 0; i < implCount; ++i)
		{
		// avoid RVCT warning C2874W: pi may be used before being set
		CAuthPluginInterface* pi = 0;

		TEComResolverParams resolverParams;
		TBufC8<16> pluginIdTxt;
		  
		pluginIdTxt.Des().Format(_L8("%x"), implInfo[i]->ImplementationUid().iUid);
		pluginIdTxt.Des().UpperCase();	  
		resolverParams.SetDataType(pluginIdTxt);
		 
		//To load plugins from sources other than ROM the patch 
		// data KEnablePostMarketAuthenticationPlugins must be set to True.
		TUint32 enablePostMarketPlugin = KEnablePostMarketAuthenticationPlugins;

#ifdef __WINS__

    	// Default SymbianOS behavior is to only load auth plugins from ROM.
		enablePostMarketPlugin = 0;

		// For the emulator allow the constant to be patched via epoc.ini
		UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
		(TAny*)"KEnablePostMarketAuthenticationPlugins", &enablePostMarketPlugin); // read emulator property (if present)

#endif			  
		TAny* plugin = 0; 
		TUid Dtor_ID_Key = TUid::Null();
		if(enablePostMarketPlugin == 0) 
			{
			TRAP(err, plugin = 
			REComSession::CreateImplementationL(KCAuthPluginInterfaceUid,
												Dtor_ID_Key,
												resolverParams,
												KRomOnlyResolverUid));
			}
			  
		else
		  	{
		  	TRAP(err, plugin = 
			REComSession::CreateImplementationL(KCAuthPluginInterfaceUid,
												Dtor_ID_Key,
												resolverParams));
		  	}
					  
		if (err == KErrAuthServNoSuchPlugin)
			continue;
		User::LeaveIfError(err);
		pi = reinterpret_cast<CAuthPluginInterface*>(plugin);	
	
		// get training status from db
		TAuthTrainingStatus ts = db->PluginStatusL(pi->Id());
		
		CleanupStack::PushL(pi);
		CPluginDesc* pd = CPluginDesc::NewL(
			pi->Id(), pi->Name(), pi->Type(),
			ts, pi->MinEntropy(),
			pi->FalsePositiveRate(), pi->FalseNegativeRate() );
		CleanupStack::PopAndDestroy(pi);
		REComSession::DestroyedImplementation(Dtor_ID_Key);
		
		CleanupStack::PushL(pd);
		aDescs.AppendL(pd);
		CleanupStack::Pop(pd);
		}
	
	CleanupStack::PopAndDestroy(2, db);
	REComSession::FinalClose();
	}


static TBool AreDescsEqual(const CPluginDesc& aLeft, const CPluginDesc& aRight)
/**
	Predicate function determines whether the two supplied
	plugin descriptions contain the same information.

	@param	aLeft			Plugin description to compare to aRight.
	@param	aRight			Plugin description to compare to aLeft.
	@return					Zero if the two descriptions contains different
							information, non-zero otherwise.
 */
	{
	return	aLeft.Id() == aRight.Id()
		&&	*aLeft.Name() == *aRight.Name()
		&&	aLeft.Type() == aRight.Type()
		&&	aLeft.TrainingStatus() == aRight.TrainingStatus()
		&&	aLeft.MinEntropy() == aRight.MinEntropy()
		&&	aLeft.FalsePositiveRate() == aRight.FalsePositiveRate()
		&&	aLeft.FalseNegativeRate() == aRight.FalseNegativeRate();
	}


inline TBool AreDescsEqual(const CPluginDesc* aLeftP, const CPluginDesc* aRightP)
	{
	return AreDescsEqual(*aLeftP, *aRightP);
	}
	

void CTStepClient::SetSeenCountsL(const RCPointerArray<const CPluginDesc>& aPlugins)
/**
	Update seenCounts array so each entry contains the
	number of times that plugin was seen in aPlugins.
 */
	{
	const TInt suppliedCount = aPlugins.Count();
	const TInt totalCount = allPlugins.Count();
	
	// i = index into seenCounts
	for (TInt i = 0; i < totalCount; ++i)
		{
		seenCounts[i] = 0;
		
		// j = index into aPlugins
		TInt j = 0;
		for (; j < suppliedCount; ++j)
			{
			if (AreDescsEqual(*allPlugins[i], *aPlugins[j]))
				{
				++seenCounts[i];
				break;		// assume plugins in allPlugins are unique
				}
			}
		
		// if plugin not found in reference set then abort
		TESTL(j < totalCount);
		}
	}


void CTStepClient::TestClientPluginListsL()
/**
	Test the expected plugins are returned when the
	client asks the server to list them.
 */
	{	
	__UHEAP_MARK;
	
	CleanupClosePushL(allPlugins);
	GetDescriptionsFromEComL(allPlugins);
	PrepareTrainedPluginsL();
	
	// re-read plugins now training statuses have been set
	allPlugins.ResetAndDestroy();	
	GetDescriptionsFromEComL(allPlugins);
	CleanupClosePushL(allPlugins);
	
	totalCount = allPlugins.Count();
	TESTL(totalCount <= KMaxSeenCount);
	
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);
	
	// ensure all plugins are returned by PluginsL
	RCPointerArray<const CPluginDesc> fullPlugins;
	ac.PluginsL(fullPlugins);
	CleanupClosePushL(fullPlugins);
	TESTL(fullPlugins.Count() == totalCount);
	SetSeenCountsL(fullPlugins);
	for (TInt k = 0; k < totalCount; ++k)
		{
		TESTL(seenCounts[k] == 1);
		}
	CleanupStack::PopAndDestroy(&fullPlugins);
	
	// ensure expected plugins are returned for each type
	TestTypedPluginsL(ac, EAuthKnowledge);
	TestTypedPluginsL(ac, EAuthBiometric);
	TestTypedPluginsL(ac, EAuthToken);

	TestActivePluginsL(ac);
	
	CleanupStack::PopAndDestroy(&ac);
	
	TestTrainedPluginsL();
	
	CleanupStack::PopAndDestroy(2, &allPlugins);
	
	__UHEAP_MARKEND;
	}


void CTStepClient::TestTypedPluginsL(RAuthClient& aClient,
									 TAuthPluginType aPluginType)
/**
	Ensure the plugin descriptions returned by the server
	match those directly seen by ECOM.
	
	@param	aPluginType		Type of plugin to retrieve.
 */
	{
	__UHEAP_MARK;
	RCPointerArray<const CPluginDesc> typedPlugins;
	aClient.PluginsOfTypeL(aPluginType, typedPlugins);
	CleanupClosePushL(typedPlugins);
	SetSeenCountsL(typedPlugins);
	
	for (TInt k = 0; k < totalCount; ++k)
		{
		TInt& recCount = seenCounts[k];
		TESTL(recCount == (allPlugins[k]->Type() == aPluginType) ? 1 : 0);
		}
	
	CleanupStack::PopAndDestroy(&typedPlugins);
	__UHEAP_MARKEND;
	}


void CTStepClient::TestActivePluginsL(RAuthClient& aClient)
/**
	Ensure the plugin descriptions returned by the server
	match those directly seen by ECOM.
 */
	{
	__UHEAP_MARK;
	RCPointerArray<const CPluginDesc> activePlugins;
	aClient.ActivePluginsL(activePlugins);
	CleanupClosePushL(activePlugins);
		
	CleanupStack::PopAndDestroy(&activePlugins);
	__UHEAP_MARKEND;
	}

void CTStepClient::TestTrainedPluginsL()
/**
	Test the expected plugins are returned when filtering
	for training types.
	
	@param	aClient			Client with open connection to auth server.
 */
	{
	RCPointerArray<const CPluginDesc> pids;
	CleanupClosePushL(pids);
	
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);
	
	const CPluginDesc* pdsc0 = allPlugins[0];
	const CPluginDesc* pdsc1 = allPlugins[1];
	const CPluginDesc* pdsc2 = allPlugins[2];
	const CPluginDesc* pdsc3 = allPlugins[3];

	ac.PluginsWithTrainingStatusL(EAuthUntrained, pids);
	TInt filterCount = pids.Count();
	TESTL(filterCount == totalCount - 4);
	for (TInt i = 0; i < filterCount; ++i)
	{
		const CPluginDesc* pidF = pids[i];
		TBool eq0 = AreDescsEqual(pidF, pdsc0);
		TBool eq1 = AreDescsEqual(pidF, pdsc1);
		TBool eq2 = AreDescsEqual(pidF, pdsc2);
		TBool eq3 = AreDescsEqual(pidF, pdsc3);
		TESTL(!eq0 && !eq1 && !eq2 && !eq3);
		}

	pids.ResetAndDestroy();
	ac.PluginsWithTrainingStatusL(EAuthTrained, pids);
	TESTL(pids.Count() == 2);
	TESTL(	(AreDescsEqual(pids[0], pdsc0) && AreDescsEqual(pids[1], pdsc1))
		||	(AreDescsEqual(pids[0], pdsc1) && AreDescsEqual(pids[1], pdsc0)) );
	
	pids.ResetAndDestroy();
	ac.PluginsWithTrainingStatusL(EAuthFullyTrained, pids);
	TESTL(pids.Count() == 2);
	TESTL(	(AreDescsEqual(pids[0], pdsc2) && AreDescsEqual(pids[1], pdsc3))
		||	(AreDescsEqual(pids[0], pdsc3) && AreDescsEqual(pids[1], pdsc2)) );
	
	CleanupStack::PopAndDestroy(2, &pids);
	}


void CTStepClient::PrepareTrainedPluginsL()
/**
	Helper function for TestTrainedPluginsL.
	
	Train some plugins so they can be filtered out later.
	This function replaces the database.
 */
	{
	// There have to be at least four available plugins
	// to run the training status test.
	TESTL(allPlugins.Count() >= 4);
	
	RemoveExistingDbL();
	CAuthDb2* db = CAuthDb2::NewLC(iFs);

	db->AddIdentityL(KIdentity1Id, KIdentity1Desc);
	db->AddIdentityL(KIdentity2Id, KIdentity2Desc);

	const CTransientKeyInfo& tki = *iId1Keys[0];
	
	// partially train plugins zero and one
	TPluginId pid0 = allPlugins[0]->Id();
	TPluginId pid1 = allPlugins[1]->Id();
	db->SetTrainedPluginL(KIdentity1Id, pid0, tki);
	db->SetTrainedPluginL(KIdentity2Id, pid1, tki);

	// fully train plugins two and three
	TPluginId pid2 = allPlugins[2]->Id();
	TPluginId pid3 = allPlugins[3]->Id();
	db->SetTrainedPluginL(KIdentity1Id, pid2, tki);
	db->SetTrainedPluginL(KIdentity2Id, pid2, tki);
	db->SetTrainedPluginL(KIdentity1Id, pid3, tki);
	db->SetTrainedPluginL(KIdentity2Id, pid3, tki);

	CleanupStack::PopAndDestroy(db);
	}

TBool CTStepClient::TestMultiAuthL()
	{
	INFO_PRINTF1(_L("Testing only a single client can make an auth "));
	INFO_PRINTF1(_L("request at any one time"));	
	
	RAuthClient ac1;
	User::LeaveIfError(ac1.Connect());
	CleanupClosePushL(ac1);

	RAuthClient ac2;
	User::LeaveIfError(ac2.Connect());
	CleanupClosePushL(ac2);

    CIdentity* result1 = 0;
    CAuthActive active1(ac1, result1, this);
    active1.doAuthenticate(KTestPluginBlocking,0);

    CIdentity* result2 = 0;
    CAuthActive active2(ac2, result2, this, EFalse);
    active2.doAuthenticate(KTestPluginBlocking,0);
	
	CActiveScheduler::Start();

    TEST(active1.iErr == KErrNone);
	TEST(active2.iErr == KErrServerBusy);
	
    delete result1;
	delete result2;
	
	CleanupStack::PopAndDestroy(2,&ac1);
	return ETrue;
	}


TBool CTStepClient::TestAuthenticateL()
/**
	Send simple authentication request.
 */
	{
	// create a transient key
	CProtectionKey* key = CProtectionKey::NewLC(8);
	CTransientKeyInfo* tki = CTransientKeyInfo::NewLC(KTestPluginId22);
	
	CTransientKey* tk = tki->CreateTransientKeyL(KIdentifyData);
	CleanupStack::PushL(tk);
	
	CEncryptedProtectionKey* epKey = tk->EncryptL(*key);
	CleanupStack::PushL(epKey);
	
	tki->SetEncryptedProtectionKeyL(epKey);
	CleanupStack::Pop(epKey);	// now owned by tki
	
	// create identity 22, which identified by test plugin
	WaitForServerToReleaseDb();
	CAuthDb2* db = CAuthDb2::NewL(iFs);
	CleanupStack::PushL(db);	
	db->AddIdentityL(22, _L("22-desc"));
	db->SetTrainedPluginL(22, KTestPluginId22, *tki);

	CleanupStack::PopAndDestroy(4, key);	// tki, tk, db
	
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);

	RAuthMgrClient amc;
	User::LeaveIfError(amc.Connect());
	CleanupClosePushL(amc);

	TInt eventId = KUnknownIdentity;
	TLastAuth lastAuth;
	TPckg<TLastAuth> lastAuthPckg(lastAuth);

	TInt err = RProperty::Get(KAuthServerSecureId, KUidAuthServerLastAuth,
							  lastAuthPckg);
	RProperty::Get(KAuthServerSecureId, KUidAuthServerAuthChangeEvent, eventId);
	TESTL(eventId == KUnknownIdentity);
	TESTL(lastAuth.iId == KUnknownIdentity);
	TESTL(lastAuth.iAuthTime == 0);
	TESTL(lastAuth.iMaxCombinations == 0);
	TESTL(lastAuth.iFalsePositiveRate == 0);
	TESTL(lastAuth.iFalseNegativeRate == 0);
	TESTL(lastAuth.iNumFactors == 0);
	
	// authenticate the client with the test plugin but using type
	
	amc.SetPreferredTypePluginL(EAuthKnowledge,
								KTestPluginId22);
    CleanupStack::PopAndDestroy(&amc);
	TESTL(KTestPluginId22 == ac.PreferredTypePluginL(EAuthKnowledge));

	CAuthExpression* ae = AuthExpr(EAuthKnowledge);		// plugin type
	User::LeaveIfNull(ae);
	CleanupStack::PushL(ae);

    CIdentity* result = 0;
    result = ac.AuthenticateL(
    	*ae,		// aExpression
    	0,			// aTimeout
    	ETrue,     // aClientSpecificKey       
		EFalse);	// aWithString
	INFO_PRINTF3(_L("1. Id = 0x%x , KeyLength = %d\n"), result->Id(),
				 result->Key().KeyData().Size());
	TESTL(result->Id() == 22);
	delete result;

	RProperty::Get(KAuthServerSecureId, KUidAuthServerLastAuth, lastAuthPckg);
	RProperty::Get(KAuthServerSecureId, KUidAuthServerAuthChangeEvent, eventId);
	TESTL(eventId == eventId);
	TESTL(lastAuth.iId == 22);
	TTime now;
	TTimeIntervalSeconds since;
	now.UniversalTime();
	now.SecondsFrom(lastAuth.iAuthTime, since);
	TESTL(since < TTimeIntervalSeconds(5));
	TESTL(lastAuth.iMaxCombinations == KEntropy);
	TESTL(lastAuth.iFalsePositiveRate == KFalsePos);
	TESTL(lastAuth.iFalseNegativeRate == KFalseNeg);
	TESTL(lastAuth.iNumFactors == 1);
	
	
	// authenticate again, to get cached value
    result = ac.AuthenticateL(
    	*ae,		// aExpression
    	55,			// aTimeout
    	ETrue,      // aClientSpecificKey
		ETrue);	    // aWithString
	TDesC p = result->String();
	INFO_PRINTF4(_L("2. Id = 0x%x , KeyLength = %d, String = %S\n"), result->Id(),
				 result->Key().KeyData().Size(), &p);
	TESTL(result->Id() == 22);
	delete result;

	
	// deauthenticate
	TRAP(err, ac.DeauthenticateL());
	TESTL(err == KErrNone);

	RProperty::Get(KAuthServerSecureId, KUidAuthServerLastAuth, lastAuthPckg);
	RProperty::Get(KAuthServerSecureId, KUidAuthServerAuthChangeEvent, eventId);
	TESTL(eventId == KUnknownIdentity);
	TESTL(lastAuth.iId == KUnknownIdentity);	
	TESTL(lastAuth.iAuthTime == 0);
	TESTL(lastAuth.iMaxCombinations == 0);
	TESTL(lastAuth.iFalsePositiveRate == 0);
	TESTL(lastAuth.iFalseNegativeRate == 0);
	TESTL(lastAuth.iNumFactors == 0);
		
    result = 0;
    CAuthActive active(ac, result, this);
    active.doAuthenticate(KTestPluginId22,0);		
	CActiveScheduler::Start();
	INFO_PRINTF3(_L("3. Id = 0x%x , KeyLength = %d"), result->Id(),
				 result->Key().KeyData().Size());
    TESTL(result->Id() == 22);
	delete result;

	
	// unknown
    result = 0;
    active.doAuthenticate(KTestPluginIdUnknown,0);		
	CActiveScheduler::Start();
	INFO_PRINTF2(_L("4. Id = 0x%x"),result->Id());
	TESTL(result->Id() == KUnknownIdentity);
	delete result;

	
	// failure (bad plugin)
    result = 0;
    active.doAuthenticate(0xD0DAD0DA,0);		
	CActiveScheduler::Start();
	INFO_PRINTF3(_L("5. CAuthActive:RunL err %d : res = 0x%x"),
				 active.iErr, result);
	TESTL(active.iErr == KErrAuthServNoSuchPlugin && result == 0);
	
	CleanupStack::PopAndDestroy(2, &ac);	// ae, ac
	return ETrue;
	}

void CTStepClient::TestSetIdentityStrL()
    {
	// assumes TestAuthenticateL has been called and id 22 is created
	RAuthClient ac;
	User::LeaveIfError(ac.Connect());
	CleanupClosePushL(ac);

	_LIT(KId22DescNew, "ID22NewDesc");

	HBufC* desc = ac.IdentityStringL(22);
	CleanupStack::PushL(desc);
	TESTL(*desc == _L("22-desc")); 
	CleanupStack::PopAndDestroy(desc); 
	
	ac.SetIdentityStringL(22, KId22DescNew);
	
	desc = ac.IdentityStringL(22);
	CleanupStack::PushL(desc); 
	TESTL(*desc == KId22DescNew); 
	CleanupStack::PopAndDestroy(desc); 
	
	CleanupStack::PopAndDestroy(&ac);
	}    

						 

TVerdict CTStepClient::doTestStepL()
	{
	if (TestStepResult() != EPass)
		return TestStepResult();
	SetTestStepResult(EPass);
	__UHEAP_MARK;
	
	CActiveScheduler::Install(iActSchd);
	
	INFO_PRINTF1(_L("Test identities"));
	TestIdentitiesL();
	
	INFO_PRINTF1(_L("Test ClientPluginLists"));
 	TestClientPluginListsL();
 	
 	INFO_PRINTF1(_L("Test Authenticate"));
	TestAuthenticateL();
	
	INFO_PRINTF1(_L("Test MultiAuth"));
	TestMultiAuthL();
	
	INFO_PRINTF1(_L("Test SetIdentityStr"));
	TestSetIdentityStrL();
	
	__UHEAP_MARKEND;	
	
	return EPass;
	}