// test long-credential authentication HRESULT CTestMessageHandler::Test4() { HRESULT hr=S_OK; CStunMessageBuilder builder1, builder2; CStunMessageReader readerResponse; CSocketAddress addrMapped; uint16_t errorcode = 0; char szNonce[MAX_STUN_AUTH_STRING_SIZE+1]; char szRealm[MAX_STUN_AUTH_STRING_SIZE+1]; // ----------------------------------------------------------------------- // simulate a user making a request with no message integrity attribute (or username, or realm) InitBindingRequest(builder1); builder1.FixLengthField(); ChkA(SendHelper(builder1, &readerResponse, _spAuthLong)); Chk(readerResponse.GetErrorCode(&errorcode)); ChkIfA(readerResponse.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED); ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED); readerResponse.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm)); readerResponse.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce)); // -------------------------------------------------------------------------------- // now simulate the follow-up request readerResponse.Reset(); InitBindingRequest(builder2); builder2.AddNonce(szNonce); builder2.AddRealm(szRealm); builder2.AddUserName("AuthorizedUser"); builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password"); builder2.FixLengthField(); ChkA(SendHelper(builder2, &readerResponse, _spAuthLong)); ChkIfA(readerResponse.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED); // should have a mapped address ChkA(readerResponse.GetMappedAddress(&addrMapped)); // and the message integrity field should be valid ChkA(readerResponse.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password")); Cleanup: return hr; }
// test simple authentication HRESULT CTestMessageHandler::Test3() { CStunMessageBuilder builder1, builder2, builder3; CStunMessageReader readerResponse; uint16_t errorcode = 0; HRESULT hr = S_OK; // ----------------------------------------------------------------------- // simulate an authorized user making a request with a valid password ChkA(InitBindingRequest(builder1)); builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser"); builder1.AddMessageIntegrityShortTerm("password"); builder1.FixLengthField(); ChkA(SendHelper(builder1, &readerResponse, _spAuthShort)); ChkA(readerResponse.ValidateMessageIntegrityShort("password")); // ----------------------------------------------------------------------- // simulate a user with a bad password readerResponse.Reset(); InitBindingRequest(builder2); builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser"); builder2.AddMessageIntegrityShortTerm("wrongpassword"); builder2.FixLengthField(); ChkA(SendHelper(builder2, &readerResponse, _spAuthShort)) errorcode = 0; ChkA(readerResponse.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_FAIL); // ----------------------------------------------------------------------- // simulate a client sending no credentials - we expect it to fire back with a 400/bad-request readerResponse.Reset(); ChkA(InitBindingRequest(builder3)); ChkA(SendHelper(builder3, &readerResponse, _spAuthShort)); errorcode = 0; ChkA(readerResponse.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, E_FAIL); Cleanup: return hr; }
// Test1 - just do a basic binding request HRESULT CTestMessageHandler::Test1() { HRESULT hr = S_OK; CStunMessageBuilder builder; CRefCountedBuffer spBuffer, spBufferOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CStunMessageReader reader; StunMessageIn msgIn; StunMessageOut msgOut; TransportAddressSet tas = {}; InitTransportAddressSet(tas, true, true, true, true); ChkA(InitBindingRequest(builder)); Chk(builder.GetResult(&spBuffer)); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); // a message send to the PP socket on the server from the msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgIn.pReader = &reader; msgIn.addrLocal = _addrServerPP; msgIn.fConnectionOriented = false; spBuffer.reset(); msgOut.spBufferOut = spBufferOut; msgOut.socketrole = RoleAA; // deliberately wrong - so we can validate if it got changed to RolePP ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, NULL)); reader.Reset(); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBufferOut->GetData(), spBufferOut->GetSize()), E_FAIL); // validate that the message returned is a success response for a binding request ChkIfA(reader.GetMessageClass() != StunMsgClassSuccessResponse, E_FAIL); ChkIfA(reader.GetMessageType() != (uint16_t)StunMsgTypeBinding, E_FAIL); // Validate that the message came from the server port we expected // and that it's the same address the server set for the origin address ChkIfA(msgOut.socketrole != RolePP, E_FAIL); ChkA(ValidateResponseOriginAddress(reader, _addrServerPP)); ChkIfA(msgOut.addrDest.IsSameIP_and_Port(_addrMapped)==false, E_FAIL); // validate that the mapping was done correctly ChkA(ValidateMappedAddress(reader, _addrMapped, false)); ChkA(ValidateOtherAddress(reader, _addrServerAA)); Cleanup: return hr; }
// Test1 - just do a basic binding request HRESULT CTestMessageHandler::Test1() { HRESULT hr=S_OK; CStunMessageBuilder builder; CSocketAddress clientaddr(0x12345678, 9876); CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; CStunMessageReader reader; CStunMessageReader::ReaderParseState state; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); InitBindingRequest(builder); builder.GetStream().GetBuffer(&spBuffer); handler.SetResponder(_spTransport); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->GetOutputStream().GetBuffer(&spBuffer); state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the binding response matches our expectations ChkA(ValidateMappedAddress(reader, clientaddr)); // validate that it came from the server port we expected ChkA(ValidateOriginAddress(reader, RolePP)); // did we get back the binding request we expected ChkA(ValidateResponseAddress(clientaddr)); Cleanup: return hr; }
// test long-credential authentication HRESULT CTestMessageHandler::Test4() { HRESULT hr=S_OK; CStunMessageBuilder builder1, builder2; CStunMessageReader reader1, reader2; CSocketAddress clientaddr(0x12345678, 9876); CSocketAddress addrMapped; CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; uint16_t errorcode = 0; char szNonce[MAX_STUN_AUTH_STRING_SIZE+1]; char szRealm[MAX_STUN_AUTH_STRING_SIZE+1]; CStunMessageReader::ReaderParseState state; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); handler.SetAuth(_spAuthLong); handler.SetResponder(_spTransport); // ----------------------------------------------------------------------- // simulate a user making a request with no message integrity attribute (or username, or realm) InitBindingRequest(builder1); builder1.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->m_outputstream.GetBuffer(&spBuffer); state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // we expect the response back will be a 401 with a provided nonce and realm Chk(reader1.GetErrorCode(&errorcode)); ChkIfA(reader1.GetMessageClass() != ::StunMsgClassFailureResponse, E_UNEXPECTED); ChkIf(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_UNEXPECTED); reader1.GetStringAttributeByType(STUN_ATTRIBUTE_REALM, szRealm, ARRAYSIZE(szRealm)); reader1.GetStringAttributeByType(STUN_ATTRIBUTE_NONCE, szNonce, ARRAYSIZE(szNonce)); // -------------------------------------------------------------------------------- // now simulate the follow-up request _spTransport->ClearStream(); spBuffer.reset(); InitBindingRequest(builder2); builder2.AddNonce(szNonce); builder2.AddRealm(szRealm); builder2.AddUserName("AuthorizedUser"); builder2.AddMessageIntegrityLongTerm("AuthorizedUser", szRealm, "password"); builder2.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->m_outputstream.GetBuffer(&spBuffer); state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); ChkIfA(reader2.GetMessageClass() != ::StunMsgClassSuccessResponse, E_UNEXPECTED); // should have a mapped address ChkA(reader2.GetMappedAddress(&addrMapped)); // and the message integrity field should be valid ChkA(reader2.ValidateMessageIntegrityLong("AuthorizedUser", szRealm, "password")); Cleanup: return hr; }
// test simple authentication HRESULT CTestMessageHandler::Test3() { HRESULT hr=S_OK; CStunMessageBuilder builder1, builder2, builder3; CStunMessageReader reader1, reader2, reader3; CSocketAddress clientaddr(0x12345678, 9876); CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; uint16_t errorcode = 0; CStunMessageReader::ReaderParseState state; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); handler.SetAuth(_spAuthShort); handler.SetResponder(_spTransport); // ----------------------------------------------------------------------- // simulate an authorized user making a request with a valid password InitBindingRequest(builder1); builder1.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "AuthorizedUser"); builder1.AddMessageIntegrityShortTerm("password"); builder1.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); handler.ProcessRequest(message); // we expect back a response with a valid message integrity field spBuffer.reset(); _spTransport->m_outputstream.GetBuffer(&spBuffer); state = reader1.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); ChkA(reader1.ValidateMessageIntegrityShort("password")); // ----------------------------------------------------------------------- // simulate a user with a bad password spBuffer.reset(); InitBindingRequest(builder2); builder2.AddStringAttribute(STUN_ATTRIBUTE_USERNAME, "WrongUser"); builder2.AddMessageIntegrityShortTerm("wrongpassword"); builder2.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); _spTransport->ClearStream(); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->m_outputstream.GetBuffer(&spBuffer); state = reader2.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); errorcode = 0; ChkA(reader2.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_UNAUTHORIZED, E_FAIL); // ----------------------------------------------------------------------- // simulate a client sending no credentials - we expect it to fire back with a 400/bad-request spBuffer.reset(); InitBindingRequest(builder3); builder3.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(message.localSocket, &(message.localAddr)); _spTransport->ClearStream(); handler.ProcessRequest(message); spBuffer.reset(); _spTransport->m_outputstream.GetBuffer(&spBuffer); state = reader3.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); errorcode = 0; ChkA(reader3.GetErrorCode(&errorcode)); ChkIfA(errorcode != ::STUN_ERROR_BADREQUEST, E_FAIL); Cleanup: return hr; }
// send a binding request to a duplex server instructing it to send back on it's alternate port and alternate IP to an alternate client port HRESULT CTestMessageHandler::Test2() { HRESULT hr=S_OK; CStunMessageBuilder builder; CSocketAddress clientaddr(0x12345678, 9876); CSocketAddress recvaddr; uint16_t responsePort = 2222; CRefCountedBuffer spBuffer; CStunThreadMessageHandler handler; CStunMessageReader reader; CStunMessageReader::ReaderParseState state; ::StunChangeRequestAttribute changereq; StunMessageEnvelope message; _spTransport->Reset(); _spTransport->AddPP(CSocketAddress(0xaaaaaaaa, 1234)); _spTransport->AddPA(CSocketAddress(0xaaaaaaaa, 1235)); _spTransport->AddAP(CSocketAddress(0xbbbbbbbb, 1234)); _spTransport->AddAA(CSocketAddress(0xbbbbbbbb, 1235)); InitBindingRequest(builder); builder.AddResponsePort(responsePort); changereq.fChangeIP = true; changereq.fChangePort = true; builder.AddChangeRequest(changereq); builder.AddResponsePort(responsePort); builder.GetResult(&spBuffer); message.localSocket = RolePP; message.remoteAddr = clientaddr; message.spBuffer = spBuffer; _spTransport->GetSocketAddressForRole(RolePP, &(message.localAddr)); handler.SetResponder(_spTransport); handler.ProcessRequest(message); spBuffer->Reset(); _spTransport->GetOutputStream().GetBuffer(&spBuffer); // parse the response state = reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the binding response matches our expectations ChkA(ValidateMappedAddress(reader, clientaddr)); ChkA(ValidateOriginAddress(reader, RoleAA)); // did it get sent back to where we thought it was recvaddr = clientaddr; recvaddr.SetPort(responsePort); ChkA(ValidateResponseAddress(recvaddr)); Cleanup: return hr; }
// Test2 - send a binding request to a duplex server instructing it to send back on it's alternate port and alternate IP to an alternate client port HRESULT CTestMessageHandler::Test2() { HRESULT hr = S_OK; CStunMessageBuilder builder; CRefCountedBuffer spBuffer, spBufferOut(new CBuffer(MAX_STUN_MESSAGE_SIZE)); CStunMessageReader reader; StunMessageIn msgIn; StunMessageOut msgOut; TransportAddressSet tas = {}; uint16_t responsePort = 2222; StunChangeRequestAttribute changereq; CStunMessageReader::ReaderParseState state; CSocketAddress addrDestExpected; InitTransportAddressSet(tas, true, true, true, true); InitBindingRequest(builder); builder.AddResponsePort(responsePort); changereq.fChangeIP = true; changereq.fChangePort = true; builder.AddChangeRequest(changereq); builder.AddResponsePort(responsePort); builder.GetResult(&spBuffer); ChkIfA(CStunMessageReader::BodyValidated != reader.AddBytes(spBuffer->GetData(), spBuffer->GetSize()), E_FAIL); msgIn.fConnectionOriented = false; msgIn.addrLocal = _addrServerPP; msgIn.pReader = &reader; msgIn.socketrole = RolePP; msgIn.addrRemote = _addrMapped; msgOut.socketrole = RolePP; // deliberate initialized wrong msgOut.spBufferOut = spBufferOut; ChkA(CStunRequestHandler::ProcessRequest(msgIn, msgOut, &tas, NULL)); // parse the response reader.Reset(); state = reader.AddBytes(spBufferOut->GetData(), spBufferOut->GetSize()); ChkIfA(state != CStunMessageReader::BodyValidated, E_FAIL); // validate that the message was sent back from the AA ChkIfA(msgOut.socketrole != RoleAA, E_FAIL); // validate that the server though it was sending back from the AA ChkA(ValidateResponseOriginAddress(reader, _addrServerAA)); // validate that the message was sent to the response port requested addrDestExpected = _addrMapped; addrDestExpected.SetPort(responsePort); ChkIfA(addrDestExpected.IsSameIP_and_Port(msgOut.addrDest)==false, E_FAIL); // validate that the binding response came back ChkA(ValidateMappedAddress(reader, _addrMapped, false)); // the "other" address is still AA (See RFC 3489 - section 8.1) ChkA(ValidateOtherAddress(reader, _addrServerAA)); Cleanup: return hr; }