std::string hashForUser(const std::string& username)
	{
		std::string password;
		if (username == "user")
		{
			password = "******";
		}
		else if (username == "admin")
		{
			password = "******";
		}
		else return "";
		
		Poco::MD5Engine md5;
		md5.update(username);
		md5.update(std::string(":poco:"));
		md5.update(password);
		std::string hashedPassword = digestToHexString(md5);

		int iterations;
		std::string salt = saltForUser(username, iterations);
		Poco::PBKDF2Engine<Poco::HMACEngine<Poco::SHA1Engine> > pbkdf2(salt, iterations, 20);
		pbkdf2.update(hashedPassword);
		return digestToBinaryString(pbkdf2);
	}
AuthenticateResult SCRAMAuthenticator::authenticate(const Credentials& creds, Poco::UInt32 conversationID)
{
	if (conversationID == 0)
	{
		conversationID = newConversationID();

		Conversation::Ptr pConv = new Conversation;
		pConv->username = creds.getAttribute(Credentials::ATTR_USERNAME);
		pConv->clientNonce = creds.getAttribute(Credentials::ATTR_NONCE);
		pConv->serverNonce = createNonce();
		pConv->salt = saltForUser(pConv->username, pConv->iterations);

		if (!pConv->salt.empty())
		{
			Credentials serverCreds;
			serverCreds.setAttribute(Credentials::ATTR_NONCE, pConv->serverNonce);
			serverCreds.setAttribute(Credentials::ATTR_SALT, pConv->salt);
			serverCreds.setAttribute(Credentials::ATTR_ITERATIONS, Poco::NumberFormatter::format(pConv->iterations));
		
			_conversations.add(conversationID, pConv);
			pConv->state = STATE_START;

			return AuthenticateResult(AuthenticateResult::AUTH_CONTINUE, serverCreds, conversationID);
		}
	}
	else
	{
		Conversation::Ptr pConv = _conversations.get(conversationID);
		if (pConv)
		{
			if (pConv->state == STATE_START)
			{
				const std::string receivedServerNonce = creds.getAttribute(Credentials::ATTR_NONCE);
				const std::string receivedClientProof = creds.getAttribute(Credentials::ATTR_PASSWORD);
				
				const std::string saltedPassword = hashForUser(pConv->username);
				std::string clientAuthMessage;
				const std::string computedClientProof = computeClientProof(pConv->username, pConv->clientNonce, pConv->salt, pConv->iterations, saltedPassword, pConv->serverNonce, clientAuthMessage);
				
				if (computedClientProof == receivedClientProof && pConv->serverNonce == receivedServerNonce)
				{
					std::string serverSignature = computeServerSignature(saltedPassword, clientAuthMessage);
					
					Credentials serverCreds;
					serverCreds.setAttribute(Credentials::ATTR_SIGNATURE, serverSignature);
					
					pConv->state = STATE_CLIENT_AUTH;
					return AuthenticateResult(AuthenticateResult::AUTH_CONTINUE, serverCreds, conversationID);		
				}
				else
				{
					_conversations.remove(conversationID);
				}
			}
			else if (pConv->state == STATE_CLIENT_AUTH)
			{
				_conversations.remove(conversationID);
				Credentials serverCreds;
				serverCreds.setAttribute(Credentials::ATTR_USERNAME, pConv->username);					
				return AuthenticateResult(AuthenticateResult::AUTH_DONE, serverCreds, conversationID);
			}
		}
	}
	return AuthenticateResult();
}