12.1.2002 NTLM library was released
Pokud ve vašich aplikacích využíváte spojení na základě socketů (v MFC CSocket a CAsyncSocket třídy) a pokud se do cesty vaší aplikaci
postaví Microsoft Proxy Server se zapnutou Windows NT Challenge/Response autentizací, vaše aplikace se pravděpodobně
nebude schopna autorizovat, jelikož NTLM autorizace není od společnosti Microsoft dokumentována.
V této situaci můžete využít knihovnu ntlm.dll, která tuto službu provádí.
Knihovna exportuje dvě funkce:
int AuthOne( char* domain, char* host, char* reply );
int AuthTwo( const char* authcode, char* domain, char* host, char* user, char* passwd, char* reply );
Autorizace je tedy rozdělena do dvou kroků. Nejlépe vše vysvětlíme na příkladu. Chtějme tedy načíst
obsah internetové adresy http://www.geniuz.cz. V prvním kroku zavoláme funkci AuthOne s parametrem domény,
ve které máme účet, v příkladu "GENIUZDOMAIN" a s parametrem host kam se chceme dostat,
tedy "www.geniuz.cz". V reply vrácený NTLM kód vložíme jako řádek hlavičky požadavku ve tvaru:
Proxy-Authorization: NTLM reply. Celá první hlavička tedy bude vypadat například následovně:
GET http://www.geniuz.cz:80/ HTTP/1.0
Accept: * / *
Host: www.geniuz.cz:80
Proxy-Connection: keep-alive
Proxy-Authorization: NTLM TlRMTVNTUAABAAAAB7IAAAsACwAtAAAA...
______ prázdný řádek
Ve vrácené hlavičce najdeme řádek podobný tomuto:
Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAFAAUADAAAAA...
Vrácenému NTLM autentikačnímu kódu říkejme authcode. V tom případě zavoláme druhou exportovanou funkci AuthTwo s parametrem
authcode (příklad - "TlRMTVNTUAACAAAAFAAUADAAAAA..."), doménou "GENIUZDOMAIN", hostem v našem případě "www.geniuz.cz",
uživatelem v příkladu "jankral" a heslem v příkladu "jan148#ca". V paremtru reply funkce AuthTwo vrátí druhý NTLM kód,
který vložíme do hlavičky a poté již proxy vrátí skutečně požadovanou stránku.
Knihovna je zkompilována pro OS Windows 32 s a nebo bez užití MFC. Rekompilace pod jiné
platformy než Windows je možná.
Získání zdrojového kódu je též možné. Pro informaci, jak si knihovnu objednat, e-mailujte na adresu
Cena knihovny je 9.000 Kč
Cena zdrojového kódu je 49.000 Kč
geniuz@geniuz.cz
Zde si můžete stáhnout testovací program.
Pro lepší orientaci a představu uvádím většinu zdrojového kódu příkladu využívajícího knihovnu ntlm.dll:
//*** exportované funkce z ntlm.dll
int AuthOne( char* domain, char* host, char* reply );
int AuthTwo( const char* authcode, char* domain, char* host, char* user, char* passwd, char* reply );
#define MAX_BUFFER_LENGTH 64000
//*** zjískání požadovaného řádku z hlavičky
CString GetHeaderStr(CString parsedName, CString header, CString parser = "\r\n", CString spacer = ": ")
{
int index = -1;
parsedName += spacer;
int len = parsedName.GetLength();
int parslen = parser.GetLength();
do index = header.Find( parsedName, index + 1 );
while (( index > 0 ? header.Mid(index-parslen,parslen) != parser : false ));
if( index >= 0 )
{
index += len;
int last = header.Find(parser, index);
if( last < 0 ) return -1;
return header.Mid(index, last - index );
}
else
return "";
}
//*** maska standartní základní hlavičky
char header_mask[] =
"GET http://%s:%d/ HTTP/1.0\r\n"
"Accept: * /*\r\n"
"Host: %s:%d\r\n"
"Proxy-Connection: keep-alive\r\n"
"Proxy-Authorization: NTLM %s\r\n"
"\r\n";
//*** poslání a načtení dat ze socketu
bool SendAndReceive( CSocket& socket, char* proxy, int port, CString& header, char* buffer )
{
if( header.GetLength() != socket.Send( header, header.GetLength() ) )
{
AfxMessageBox( "Send error" );
return false;
}
if( 0 > socket.Receive( buffer, MAX_BUFFER_LENGTH ) )
{
AfxMessageBox( "Receive error" );
return false;
}
return true;
}
//*** ukázka NTLM autentikace
void Ntlm()
{
CString header;
//*** smyšlená autentikační data
char domain[] = "GENIUZDOMAIN";
char user[] = "jankral";
char passwd[] = "jan148#ca";
char host[] = "www.geniuz.cz";
char hostport = 80;
char proxy[] = "PROXY";
char proxyport = 80;
char buffer[ MAX_BUFFER_LENGTH ] = "\x00";
char ntlm[256];
//*** vytvoření socketu
CSocket socket;
if( !socket.Create() )
{ AfxMessageBox( "Create error" ); return; }
if( !socket.Connect( proxy, proxyport ) )
{ AfxMessageBox( "Connect error" ); return; }
//*** první autorizace z ntlm.dll
AuthOne( domain, host, ntlm );
//*** zformátování hlacičky
header.Format( header_mask, host, hostport, host, hostport, ntlm );
//*** odeslání hlavičky a získání odpovědi
if( !SendAndReceive(socket, proxy, proxyport, header, buffer) ) return;
//*** zjískání autentikačního kódu z vrácené hlavičky
CString response = GetHeaderStr( "Proxy-Authenticate", buffer );
//*** druhá autorizace z ntlm.dll
AuthTwo( response.Mid(5), domain, host, user, passwd, ntlm );
//*** zformátování hlacičky
header.Format( header_mask, host, hostport, host, hostport, ntlm );
//*** odeslání hlavičky a získání odpovědi
if( !SendAndReceive(socket, proxy, proxyport, header, buffer) ) return;
socket.Close();
//*** buffer obsahuje skutečnou stánku po předchozí NTLM autorizaci
AfxMessageBox( buffer );
}
|