📄 casisapi.cpp
字号:
/*
Developer: Jim Klopfenstein Date: 12/17/02
Name: CASIsapi.cpp
Function: ISAPI filter to provide CAS client functionality on IIS
*Change Log*
Developer: Date: Comments
Alan Walsh 12/20/02 Started using basic string class instead of char* in some places
in order to eliminate use of unsafe strX functions (e.g. strcat)
Alan Walsh 12/20/02 Added support for IUCAS appcode (e.g. cassvc="MY") in querystring
Alan Walsh 01/03/03 Added calls to CryptDestroyKey and CryptReleaseContext in destructor
Jim K 01/28/03 Made string comparison in DoesAuthApply case-insensitive
Jim K 01/28/03 In InitEncryption, add second CryptAcquireContext if first fails
Jim K 01/28/03 In OnAuthComplete, replace all "goto authcontinues" with
"return SF_STATUS_REQ_ERROR" to avoid race condition
Jim K 01/30/03 Back off from basic string class, but replace strcpy with
safestrcpy and strcat with safestrcat
Jim K 01/30/03 Remove dependencies on MFC wrapper class
Jim K 01/30/03 New bInit variable traps initialization success/failure;
custom HTML page is returned for all access after failure
Jim K 02/05/03 Added event logging
Jim K 02/07/03 Remove ticket parameter from query string before redirect
Jim K 02/12/03 Added "excludeFromStartOfURL" to work around ColdFusion MX bug
Jim K 02/12/03 Added bSuccessful check in Init to catch malformed XML
Jim K 03/10/03 Added secure cookie, requiresSSL parameter and checks for it
Jim K 04/02/03 Handle CRLF as line break in response file (as well as just LF)
Jim K 04/28/03 Redirect via HTTP 307 return code on HTTP 1.1 POSTs
*/
#include "stdafx.h"
#include <httpfilt.h>
#include <wincrypt.h>
#include <time.h>
#include "C:\Program Files\MSXML 4.0\inc\msxml2.h"
#include "CasIsapiMsg.h"
static char* pValidateURL;
static char* pLoginURL;
static char* pAppParamName;
static char* pServiceParamName;
static char* pTicketParamName;
static char* pTicketParamSearchValue;
static char* pAppCode;
static int cookieTimeout;
static long resolveTimeout;
static long connectTimeout;
static long sendTimeout;
static long receiveTimeout;
static char* pEncryptionPassword;
static char* pSecurityTriggerFile;
static size_t lenTriggerFile;
static char* pExcludeFromStartOfURL = NULL;
static bool InitEncryption();
static char* decryptCookie(char* pCypherText);
static char* safestrcat(char* to,const char* from,size_t len);
static char* safestrcpy(char* to,const char* from,size_t len);
static int str2int(char* instr);
static long str2long(char* instr);
static void hexEncode(BYTE* inBytes,DWORD len,char* outBuf);
static void hexEncodeInPlace(BYTE* inBytes,DWORD len);
static void hexDecode(char* inBuf,BYTE* outBuf);
static DWORD encryptLength(char* pPlainText);
static bool encryptCookie(char* pPlainText,DWORD encryptLen);
static bool AddEventSource();
static void ReportInitError(char* szMsg);
static void ReportInitSuccess();
static void ReportRedirect(char* szMsg);
static void ReportValidation(char* szMsg1,char* szMsg2);
static void ReportCookieAuthentication(char* szMsg1,char* szMsg2);
static void ReportApplyDecision(char* szMsg1,char* szMsg2,char* szMsg3);
//CryptoAPI elements
static HCRYPTPROV hProv = 0;
static HCRYPTKEY hKey = 0;
static bool bInit = true;
static bool bSecure = true;
static char* pFailReason = NULL;
const char* pConfigError = "Error in configuration file";
const char* pEventLogError = "Error configuring event log";
const char* pXMLHTTPError = "Error instantiating XMLHTTP object";
const char* pMissingConfigParameter = "Configuration parameter missing";
const char* pEncryptError = "Error initializing encryption";
static char* ConfigValueHelper(wchar_t* paramName,IXMLDOMDocument* pXmlDoc)
{
IXMLDOMNode *pResultNode;
IXMLDOMElement* pDomElement;
char* pszReturn;
size_t len;
BSTR bstrText;
if (FAILED(pXmlDoc->get_documentElement(&pDomElement))) {return NULL;}
if (FAILED(pDomElement->selectSingleNode(paramName,&pResultNode)))
{
pDomElement->Release();
return NULL;
}
if (pResultNode == NULL)
return NULL;
if (FAILED(pDomElement->Release())) {return NULL;}
if (FAILED(pResultNode->get_text(&bstrText))) {return NULL;}
len = wcslen(bstrText) + 1;
if (NULL == (pszReturn=(char*)malloc(len))) {return NULL;}
wcstombs(pszReturn,bstrText,len);
SysFreeString(bstrText);
if (FAILED(pResultNode->Release())) {return NULL;}
return pszReturn;
}
static void Init()
{
VARIANT_BOOL bSuccessful;
VARIANT xmlSource;
char* pTemp;
IXMLDOMDocument* pXmlDoc;
IServerXMLHTTPRequest2 *pRequest;
size_t alloclen;
if (!AddEventSource())
{
bInit = false;
return;
}
pFailReason = (char*)pXMLHTTPError;
if (FAILED(CoCreateInstance(CLSID_ServerXMLHTTP40,NULL,CLSCTX_INPROC_SERVER,IID_IServerXMLHTTPRequest,(LPVOID*)&pRequest)))
{
bInit = false;
return;
}
pRequest->Release();
pFailReason = (char*)pConfigError;
if (FAILED(CoCreateInstance(CLSID_DOMDocument,NULL,CLSCTX_INPROC_SERVER,IID_IXMLDOMDocument,(LPVOID*)&pXmlDoc))) {
bInit = false;
return;
}
if (NULL == (xmlSource.bstrVal=SysAllocString(L"casisapi.config")))
{
bInit = false;
pXmlDoc->Release();
return;
}
xmlSource.vt = VT_BSTR;
if (FAILED(pXmlDoc->load(xmlSource,&bSuccessful)))
{
bInit = false;
pXmlDoc->Release();
pXmlDoc = NULL;
SysFreeString(xmlSource.bstrVal);
return;
}
SysFreeString(xmlSource.bstrVal);
if (!bSuccessful) {bInit=false; return; }
pFailReason = (char*)pMissingConfigParameter;
if (NULL != (pTemp=ConfigValueHelper(L"httpsRequired",pXmlDoc)))
{
if (!stricmp(pTemp,"no"))
bSecure = false;
free(pTemp);
}
if (NULL == (pValidateURL=ConfigValueHelper(L"validation/URL",pXmlDoc))) {bInit = false; return; }
if (NULL == (pLoginURL=ConfigValueHelper(L"loginURL",pXmlDoc))) {bInit = false; return; }
if (NULL == (pAppParamName=ConfigValueHelper(L"appParamName",pXmlDoc))) {bInit = false; return; }
if (NULL == (pServiceParamName=ConfigValueHelper(L"serviceParamName",pXmlDoc))) {bInit = false; return; }
if (NULL == (pTicketParamName=ConfigValueHelper(L"ticketParamName",pXmlDoc))) {bInit = false; return; }
alloclen = strlen(pTicketParamName) + 2;
pTicketParamSearchValue=(char*)malloc(alloclen);
if (NULL == (pAppCode=ConfigValueHelper(L"appCode",pXmlDoc))) {bInit = false; return; }
safestrcpy(pTicketParamSearchValue,pTicketParamName,alloclen);
safestrcat(pTicketParamSearchValue,"=",alloclen);
pExcludeFromStartOfURL = ConfigValueHelper(L"excludeFromStartOfURL",pXmlDoc);
if (NULL != (pTemp=ConfigValueHelper(L"cookieTimeout",pXmlDoc)))
{
cookieTimeout = str2int(pTemp);
free(pTemp);
}
if (NULL != (pTemp=ConfigValueHelper(L"validation/resolveTimeout",pXmlDoc)))
{
resolveTimeout = str2long(pTemp);
free(pTemp);
}
if (NULL != (pTemp=ConfigValueHelper(L"validation/connectTimeout",pXmlDoc)))
{
connectTimeout = str2long(pTemp);
free(pTemp);
}
if (NULL != (pTemp=ConfigValueHelper(L"validation/sendTimeout",pXmlDoc)))
{
sendTimeout = str2long(pTemp);
free(pTemp);
}
if (NULL != (pTemp=ConfigValueHelper(L"validation/receiveTimeout",pXmlDoc)))
{
receiveTimeout = str2long(pTemp);
free(pTemp);
}
if (NULL == (pEncryptionPassword=ConfigValueHelper(L"encryptionPassword",pXmlDoc))) {bInit = false; return; }
if (NULL == (pSecurityTriggerFile=ConfigValueHelper(L"securityTriggerFile",pXmlDoc))) {bInit = false; return; }
lenTriggerFile = strlen(pSecurityTriggerFile);
pFailReason = (char*)pEncryptError;
if (!InitEncryption()) {bInit = false;};
pFailReason = NULL;
}
extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
{
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
pVer->dwFlags = SF_NOTIFY_ORDER_HIGH | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_AUTH_COMPLETE;
pVer->lpszFilterDesc[0] = '\0';
Init();
if (bInit)
ReportInitSuccess();
else if (pFailReason)
ReportInitError(pFailReason);
else
{
pFailReason = (char*)pEventLogError;
}
return TRUE;
}
#define STACK_ALLOC_SERVER_VARIABLE(variable,target) \
size = 0; \
if (!pCtxt->GetServerVariable(pCtxt,variable,NULL,(LPDWORD)&size)) \
{ \
dwLastError = GetLastError(); \
if (122 == dwLastError) \
{ \
if (NULL != (target = (char*)_alloca(size))) \
if (!pCtxt->GetServerVariable(pCtxt,variable,target,(LPDWORD)&size)) \
target = NULL; \
} \
else \
target = NULL; \
}
#define STACK_ALLOC_HEADER(header,target) \
size = 0; \
if (!(*pParms->GetHeader)(pCtxt,header,NULL,&size)) \
{ \
dwLastError = GetLastError(); \
if (122 == dwLastError) \
{ \
if (NULL != (target = (char*)_alloca(size))) \
if (!(*pParms->GetHeader)(pCtxt,header,target,&size)) \
target = NULL; \
} \
else \
target = NULL; \
}
static char *CheckCookie(char* pCookie,char* pRemoteAddr)
{
char *s;
char *pCookieRemoteAddr;
time_t timer,cookieTime;
for (s=pCookie; *s && *s != '|'; s++) ;
if (*s = '\0') {return NULL;}
*(s++) = '\0';
pCookieRemoteAddr = s;
for (; *s && *s != '|'; s++) ;
*(s++) = '\0';
if (strcmp(pRemoteAddr,pCookieRemoteAddr)) {return NULL;}
hexDecode(s,(BYTE*)&cookieTime);
if (&cookieTime == 0) {return NULL;}
time(&timer);
if ((cookieTime >= timer) || ((timer - cookieTime) > cookieTimeout)) {return NULL;}
return pCookie;
}
static bool DoesAuthApplyToFile(PHTTP_FILTER_CONTEXT pCtxt)
{
DWORD size;
BOOL authOkay = false;
DWORD dwLastError;
char *pPathTranslated;
char *pScriptName;
char *pFileSpec;
char *s;
char *pLastSlash;
size_t lenPathTranslated;
size_t lenScriptName;
size_t alloclen;
STACK_ALLOC_SERVER_VARIABLE("PATH_TRANSLATED",pPathTranslated);
if (pPathTranslated == NULL) {return true;}
lenPathTranslated = strlen(pPathTranslated);
STACK_ALLOC_SERVER_VARIABLE("SCRIPT_NAME",pScriptName);
if (pScriptName == NULL) {return true;}
lenScriptName = strlen(pScriptName);
for (s=pPathTranslated; *s; s++) ;
for (--s; (s >=pPathTranslated) && (*s != '.') && (*s != '\\'); s--) ;
if (*s == '.')
{
alloclen = lenPathTranslated+lenTriggerFile+1;
pFileSpec = (char*)_alloca(alloclen);
if (pFileSpec == NULL) {return true;}
safestrcpy(pFileSpec,pPathTranslated,alloclen);
}
else
{
for (s=pScriptName; s && *s; s++)
if (*s == '/')
*s = '\\';
// s = (lenPathTranslated > lenScriptName) ? &pPathTranslated[lenPathTranslated-lenScriptName] : "";
alloclen = lenPathTranslated+lenScriptName+lenTriggerFile+1;
pFileSpec = (char*)_alloca(alloclen);
if (pFileSpec == NULL) {return true;}
safestrcpy(pFileSpec,pPathTranslated,alloclen);
safestrcat(pFileSpec,pScriptName,alloclen);
}
for (s=pFileSpec;s && *s; s++)
if (*s == '\\') {pLastSlash = s;}
*(++pLastSlash) = '\0';
safestrcat(pFileSpec,pSecurityTriggerFile,alloclen);
// ReportApplyDecision(pPathTranslated,pScriptName,pFileSpec);
HANDLE hFile = CreateFile(pFileSpec,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hFile) {return false;}
CloseHandle(hFile);
return true;
}
extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pCtxt,
DWORD dwNotificationType, LPVOID pvNotification)
{
PHTTP_FILTER_AUTH_COMPLETE_INFO pParms = (PHTTP_FILTER_AUTH_COMPLETE_INFO)pvNotification;
DWORD size;
BOOL authOkay = false;
DWORD dwLastError;
char *pRemoteAddr;
char *pCookie;
char *pQueryString;
char *pURL;
char *pServerName;
char *pServerPort;
char *pRequestMethod;
char *pServerProtocol;
char *pHTTPS;
const char* pHeaders1 = "Content-Type: text/html";
const char* pHeaders1a = "Location: ";
const char* pHeaders2 = "\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nExpires: Fri, 01-Jan-1970 00:00:01 GMT\r\n\r\n";
const char* pBoilerplate1 = "<html><body><h3>Authentication Filter Error</h3>\r\n<p>";
const char* pBoilerplate2 = "</p></body></html>";
if (!bInit)
{
char *pHeaders;
DWORD writeLen;
size_t alloclen = strlen(pHeaders1)+strlen(pHeaders2)+1;
pHeaders = (char*)_alloca(alloclen);
safestrcpy(pHeaders,pHeaders1,alloclen);
safestrcat(pHeaders,pHeaders2,alloclen);
pCtxt->AddResponseHeaders(pCtxt,pHeaders,0);
pCtxt->ServerSupportFunction(pCtxt,SF_REQ_SEND_RESPONSE_HEADER,
"200 OKAY",NULL,NULL);
writeLen = (DWORD)strlen(pBoilerplate1);
pCtxt->WriteClient(pCtxt,(LPVOID)pBoilerplate1,&writeLen,NULL);
writeLen = (DWORD)strlen(pFailReason);
pCtxt->WriteClient(pCtxt,(LPVOID)pFailReason,&writeLen,NULL);
writeLen = (DWORD)strlen(pBoilerplate2);
pCtxt->WriteClient(pCtxt,(LPVOID)pBoilerplate2,&writeLen,NULL);
return SF_STATUS_REQ_FINISHED;
}
if (!DoesAuthApplyToFile(pCtxt)) {return SF_STATUS_REQ_NEXT_NOTIFICATION;}
STACK_ALLOC_SERVER_VARIABLE("REMOTE_ADDR",pRemoteAddr)
if (pRemoteAddr == NULL) {return SF_STATUS_REQ_ERROR;}
STACK_ALLOC_HEADER("Cookie:",pCookie)
// if request includes cookies
if (pCookie)
{
char *s;
char *t;
if (s=strstr(pCookie,"UITSAUTH=")) // our cookie is present
{
char* pOurCookie;
char* pUserName;
char* pPlainCookie;
for (t=s+9; *t && *t != ';'; t++) ;
*t = '\0';
pOurCookie = s+9;
pPlainCookie = decryptCookie(pOurCookie);
if ((NULL != pPlainCookie) && (pUserName=CheckCookie(pPlainCookie,pRemoteAddr)))
{
STACK_ALLOC_HEADER("URL",pURL);
if (pURL == NULL) {return SF_STATUS_REQ_ERROR;}
ReportCookieAuthentication(pURL,pUserName);
if (!(*pParms->SetHeader)(pCtxt,"user:",pUserName)) {return SF_STATUS_REQ_ERROR;}
authOkay = true;
}
}
}
if (!authOkay)
{
STACK_ALLOC_SERVER_VARIABLE("QUERY_STRING",pQueryString)
if (NULL == pQueryString) {
return SF_STATUS_REQ_ERROR;
}
else
{
STACK_ALLOC_SERVER_VARIABLE("HTTPS",pHTTPS);
if (pHTTPS == NULL) {return SF_STATUS_REQ_ERROR;}
strcpy(pHTTPS,strcmp(pHTTPS,"on")? "" : "s");
STACK_ALLOC_SERVER_VARIABLE("SERVER_NAME",pServerName);
if (pServerName == NULL) {return SF_STATUS_REQ_ERROR;}
STACK_ALLOC_SERVER_VARIABLE("SERVER_PORT",pServerPort);
if (pServerPort == NULL) {return SF_STATUS_REQ_ERROR;}
if (!strcmp(pServerPort,"80") && (pHTTPS[0] == '\0')) {pServerPort[0] = '\0';}
if (!strcmp(pServerPort,"443") && (pHTTPS[0] == 's')) {pServerPort[0] = '\0';}
if (strstr(pQueryString,pTicketParamSearchValue))
{
char* pValidateQuery;
IServerXMLHTTPRequest2 *pRequest;
HRESULT hr;
time_t timer;
size_t len;
wchar_t* pWBuf;
BSTR bMethod;
BSTR bUrl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -