ClearBox Server™ v1.2 Developer's Guide

Step 7. Implementing RADIUS and TACACS+ Authentication

On this step we implement methods of IRADIUSAuthentication and ITACACSAuthentication interfaces. We use them to control allowed authentication methods.

1. Create with a Add Function... wizard a method common for TACACS+ and RADIUS that authenticated user and checks if their accounts are valid.

Set the following parameters:

  • Access type - protected
  • Return type - bool
  • Function name - CheckAuthentication
  • Parameter 1 - AUTHENTYPE authType
  • Parameter 2 - CString userName
  • Parameter 3 - CString& explainString

Set its body to the following:

bool CheckAuthentication(AUTHENTYPE authType, CString userName, CString& explainString)
{
	bool res=false;
	switch(authType)
	{
	case AT_ASCII:
	case AT_PAP:
		res=m_PAPallowed;
		break;
	case AT_CHAP:
		res=m_CHAPallowed;
		break;
	case AT_MSCHAP:
		res=m_MSCHAPallowed;
		break;
	case AT_MSCHAPv2:
		res=m_MSCHAP2allowed;
		break;
	}
	if (!res)
	{
		explainString=_T("Unallowed authentication method");
		return false;
	}
	if (m_AuthenType!=db)
		return true;

	CCommand cmd;
	CString cmdString;
	cmdString.Format(_T("select Enabled, ValidSince, ValidTill from Users where Name='%s'"),
		userName);
	HRESULT hr=cmd.Open(m_DB.Session(),cmdString);
	if (FAILED(hr))
		return false;
	hr=cmd.MoveFirst();
	if (hr!=S_OK)
		return false;
	VARIANT_BOOL* valid=(VARIANT_BOOL*)cmd.GetValue(1);
	DATE* since=(DATE*)cmd.GetValue(2);
	DATE* till=(DATE*)cmd.GetValue(3);

	if (*valid==VARIANT_FALSE)
	{
		explainString=_T("User account is disabled");
		return false;
	}
	COleDateTime dtSince((DATE)*since);
	COleDateTime dtTill((DATE)*till);
	if (dtSince.m_dt!=0 && dtSince>COleDateTime::GetCurrentTime())
	{
		explainString=_T("User account is not valid yet");
		return false;
	}
	if (dtTill.m_dt!=0 && COleDateTime::GetCurrentTime()>dtTill)
	{
		explainString=_T("User account is not valid already");
		return false;
	}
	return true;
}
	  

First it checks whether some authentication was allowed in settings.ini file or not. If it's not allowed, user is rejected. Next if authentication is made through a database, user account is queried. User is rejected if Enabled field is false, if ValidSince is not null and is greater than current time or ValidTill time has expired.

2. Double-click first CanAuthenticate child node of CExtension in the Class View window. Change this method to the following:

STDMETHOD(CanAuthenticate)(long tag, AUTHENTYPE authType, USERINFOLITE * userInf, 
	BSTR * explainString, RADAUTHENREPLY * AUTHENRESULT)
{
	USES_CONVERSION;
	CString expStr;
	bool res=CheckAuthentication(authType,W2T(userInf->userName),expStr);

	if (!res)
	{
		*AUTHENRESULT=ACCESS_REJECT;
		*explainString=expStr.AllocSysString();
	}
	else
		*AUTHENRESULT=ACCESS_ACCEPT;

	return S_OK;
}
		

This method calls CheckAuthentication function we've just created.

3. Next we implement ITACACSAuthentication::CanAuthenticate in almost the same way:

STDMETHOD(CanAuthenticate)(long tag, TAC_AUTHEN_LITE * authenParams, 
	BSTR * explainString, unsigned char * tacacsStatus)
{
	USES_CONVERSION;
	CString expStr;
	bool res=CheckAuthentication((AUTHENTYPE)authenParams->authentication_type,
		W2T(authenParams->user),expStr);

	if (!res)
	{
		*tacacsStatus=TAC_PLUS_AUTHEN_STATUS_FAIL;
		*explainString=expStr.AllocSysString();
	}
	else
		*tacacsStatus=TAC_PLUS_AUTHEN_STATUS_PASS;

	return S_OK;
}
		

The only trick here is to cast authentication_type to AUTHENTYPE enumeration as they have the same values.

4. Finally we have to make GetRejectResponseAttributes, GetChallengeResponseAttributes and ChallengeDataReply methods return S_OK as we need not to implement them.

Now our server extension is capable of authenticating users.

Go to the next step.


© 2001-2003 XPerience Technologies. www.xperiencetech.com

Created by chm2web html help conversion utility.