Added support for initial response in SASL authentication.
This commit is contained in:
parent
c655495025
commit
c860c273d3
@ -355,7 +355,26 @@ void IMAPConnection::authenticateSASL()
|
|||||||
|
|
||||||
saslSession->init();
|
saslSession->init();
|
||||||
|
|
||||||
send(true, "AUTHENTICATE " + mech->getName(), true);
|
std::ostringstream cmd;
|
||||||
|
cmd << "AUTHENTICATE " << mech->getName();
|
||||||
|
|
||||||
|
if (saslSession->getMechanism()->hasInitialResponse())
|
||||||
|
{
|
||||||
|
byte_t* initialResp = 0;
|
||||||
|
size_t initialRespLen = 0;
|
||||||
|
|
||||||
|
saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
|
||||||
|
|
||||||
|
string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
|
||||||
|
delete [] initialResp;
|
||||||
|
|
||||||
|
if (encodedInitialResp.empty())
|
||||||
|
cmd << " =";
|
||||||
|
else
|
||||||
|
cmd << " " << encodedInitialResp;
|
||||||
|
}
|
||||||
|
|
||||||
|
send(true, cmd.str(), true);
|
||||||
|
|
||||||
for (bool cont = true ; cont ; )
|
for (bool cont = true ; cont ; )
|
||||||
{
|
{
|
||||||
|
@ -73,6 +73,17 @@ shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName, const string& initialResponse)
|
||||||
|
{
|
||||||
|
std::ostringstream cmd;
|
||||||
|
cmd.imbue(std::locale::classic());
|
||||||
|
cmd << "AUTH " << mechName << " " << initialResponse;
|
||||||
|
|
||||||
|
return createCommand(cmd.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
shared_ptr <POP3Command> POP3Command::STLS()
|
shared_ptr <POP3Command> POP3Command::STLS()
|
||||||
{
|
{
|
||||||
|
@ -57,6 +57,7 @@ public:
|
|||||||
static shared_ptr <POP3Command> CAPA();
|
static shared_ptr <POP3Command> CAPA();
|
||||||
static shared_ptr <POP3Command> NOOP();
|
static shared_ptr <POP3Command> NOOP();
|
||||||
static shared_ptr <POP3Command> AUTH(const string& mechName);
|
static shared_ptr <POP3Command> AUTH(const string& mechName);
|
||||||
|
static shared_ptr <POP3Command> AUTH(const string& mechName, const string& initialResponse);
|
||||||
static shared_ptr <POP3Command> STLS();
|
static shared_ptr <POP3Command> STLS();
|
||||||
static shared_ptr <POP3Command> APOP(const string& username, const string& digest);
|
static shared_ptr <POP3Command> APOP(const string& username, const string& digest);
|
||||||
static shared_ptr <POP3Command> USER(const string& username);
|
static shared_ptr <POP3Command> USER(const string& username);
|
||||||
|
@ -446,7 +446,29 @@ void POP3Connection::authenticateSASL()
|
|||||||
|
|
||||||
saslSession->init();
|
saslSession->init();
|
||||||
|
|
||||||
POP3Command::AUTH(mech->getName())->send(dynamicCast <POP3Connection>(shared_from_this()));
|
shared_ptr <POP3Command> authCmd;
|
||||||
|
|
||||||
|
if (saslSession->getMechanism()->hasInitialResponse())
|
||||||
|
{
|
||||||
|
byte_t* initialResp = 0;
|
||||||
|
size_t initialRespLen = 0;
|
||||||
|
|
||||||
|
saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
|
||||||
|
|
||||||
|
string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
|
||||||
|
delete [] initialResp;
|
||||||
|
|
||||||
|
if (encodedInitialResp.empty())
|
||||||
|
authCmd = POP3Command::AUTH(mech->getName(), "=");
|
||||||
|
else
|
||||||
|
authCmd = POP3Command::AUTH(mech->getName(), encodedInitialResp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
authCmd = POP3Command::AUTH(mech->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
authCmd->send(dynamicCast <POP3Connection>(shared_from_this()));
|
||||||
|
|
||||||
for (bool cont = true ; cont ; )
|
for (bool cont = true ; cont ; )
|
||||||
{
|
{
|
||||||
|
@ -79,6 +79,17 @@ shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName, const std::string& initialResponse)
|
||||||
|
{
|
||||||
|
std::ostringstream cmd;
|
||||||
|
cmd.imbue(std::locale::classic());
|
||||||
|
cmd << "AUTH " << mechName << " " << initialResponse;
|
||||||
|
|
||||||
|
return createCommand(cmd.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
shared_ptr <SMTPCommand> SMTPCommand::STARTTLS()
|
shared_ptr <SMTPCommand> SMTPCommand::STARTTLS()
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,7 @@ public:
|
|||||||
static shared_ptr <SMTPCommand> HELO(const string& hostname);
|
static shared_ptr <SMTPCommand> HELO(const string& hostname);
|
||||||
static shared_ptr <SMTPCommand> EHLO(const string& hostname);
|
static shared_ptr <SMTPCommand> EHLO(const string& hostname);
|
||||||
static shared_ptr <SMTPCommand> AUTH(const string& mechName);
|
static shared_ptr <SMTPCommand> AUTH(const string& mechName);
|
||||||
|
static shared_ptr <SMTPCommand> AUTH(const string& mechName, const std::string& initialResponse);
|
||||||
static shared_ptr <SMTPCommand> STARTTLS();
|
static shared_ptr <SMTPCommand> STARTTLS();
|
||||||
static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8);
|
static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8);
|
||||||
static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, const size_t size);
|
static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, const size_t size);
|
||||||
|
@ -367,7 +367,25 @@ void SMTPConnection::authenticateSASL()
|
|||||||
|
|
||||||
saslSession->init();
|
saslSession->init();
|
||||||
|
|
||||||
|
if (saslSession->getMechanism()->hasInitialResponse())
|
||||||
|
{
|
||||||
|
byte_t* initialResp = 0;
|
||||||
|
size_t initialRespLen = 0;
|
||||||
|
|
||||||
|
saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
|
||||||
|
|
||||||
|
string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
|
||||||
|
delete [] initialResp;
|
||||||
|
|
||||||
|
if (encodedInitialResp.empty())
|
||||||
|
sendRequest(SMTPCommand::AUTH(mech->getName(), "="));
|
||||||
|
else
|
||||||
|
sendRequest(SMTPCommand::AUTH(mech->getName(), encodedInitialResp));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
sendRequest(SMTPCommand::AUTH(mech->getName()));
|
sendRequest(SMTPCommand::AUTH(mech->getName()));
|
||||||
|
}
|
||||||
|
|
||||||
for (bool cont = true ; cont ; )
|
for (bool cont = true ; cont ; )
|
||||||
{
|
{
|
||||||
|
@ -58,6 +58,9 @@ public:
|
|||||||
* server (challenge), process it and return data to be returned
|
* server (challenge), process it and return data to be returned
|
||||||
* in response to the server.
|
* in response to the server.
|
||||||
*
|
*
|
||||||
|
* If the challenge is empty (challengeLen == 0), the initial
|
||||||
|
* response is returned, if this mechanism has one.
|
||||||
|
*
|
||||||
* @param sess SASL session
|
* @param sess SASL session
|
||||||
* @param challenge challenge sent from the server
|
* @param challenge challenge sent from the server
|
||||||
* @param challengeLen length of challenge
|
* @param challengeLen length of challenge
|
||||||
@ -84,6 +87,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool isComplete() const = 0;
|
virtual bool isComplete() const = 0;
|
||||||
|
|
||||||
|
/** Determine if this mechanism has an optional initial response.
|
||||||
|
* If true, caller should call step() with an empty challenge to
|
||||||
|
* get the initial response.
|
||||||
|
*
|
||||||
|
* @return true if this mechanism has an initial response, or
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool hasInitialResponse() const = 0;
|
||||||
|
|
||||||
/** Encode data according to negotiated SASL mechanism. This
|
/** Encode data according to negotiated SASL mechanism. This
|
||||||
* might mean that data is integrity or privacy protected.
|
* might mean that data is integrity or privacy protected.
|
||||||
*
|
*
|
||||||
|
@ -96,6 +96,9 @@ public:
|
|||||||
* server (challenge), process it and return data to be returned
|
* server (challenge), process it and return data to be returned
|
||||||
* in response to the server.
|
* in response to the server.
|
||||||
*
|
*
|
||||||
|
* If the challenge is empty (challengeLen == 0), the initial
|
||||||
|
* response is returned, if the mechanism has one.
|
||||||
|
*
|
||||||
* @param challenge challenge sent from the server
|
* @param challenge challenge sent from the server
|
||||||
* @param challengeLen length of challenge
|
* @param challengeLen length of challenge
|
||||||
* @param response response to send to the server (allocated by
|
* @param response response to send to the server (allocated by
|
||||||
|
@ -120,6 +120,13 @@ bool builtinSASLMechanism::isComplete() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool builtinSASLMechanism::hasInitialResponse() const
|
||||||
|
{
|
||||||
|
// It seems GNU SASL does not support initial response
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void builtinSASLMechanism::encode
|
void builtinSASLMechanism::encode
|
||||||
(shared_ptr <SASLSession> sess, const byte_t* input, const size_t inputLen,
|
(shared_ptr <SASLSession> sess, const byte_t* input, const size_t inputLen,
|
||||||
byte_t** output, size_t* outputLen)
|
byte_t** output, size_t* outputLen)
|
||||||
|
@ -61,6 +61,8 @@ public:
|
|||||||
|
|
||||||
bool isComplete() const;
|
bool isComplete() const;
|
||||||
|
|
||||||
|
bool hasInitialResponse() const;
|
||||||
|
|
||||||
void encode(shared_ptr <SASLSession> sess,
|
void encode(shared_ptr <SASLSession> sess,
|
||||||
const byte_t* input, const size_t inputLen,
|
const byte_t* input, const size_t inputLen,
|
||||||
byte_t** output, size_t* outputLen);
|
byte_t** output, size_t* outputLen);
|
||||||
|
@ -39,6 +39,7 @@ VMIME_TEST_SUITE_BEGIN(POP3CommandTest)
|
|||||||
VMIME_TEST(testCAPA)
|
VMIME_TEST(testCAPA)
|
||||||
VMIME_TEST(testNOOP)
|
VMIME_TEST(testNOOP)
|
||||||
VMIME_TEST(testAUTH)
|
VMIME_TEST(testAUTH)
|
||||||
|
VMIME_TEST(testAUTH_InitialResponse)
|
||||||
VMIME_TEST(testSTLS)
|
VMIME_TEST(testSTLS)
|
||||||
VMIME_TEST(testAPOP)
|
VMIME_TEST(testAPOP)
|
||||||
VMIME_TEST(testUSER)
|
VMIME_TEST(testUSER)
|
||||||
@ -97,6 +98,14 @@ VMIME_TEST_SUITE_BEGIN(POP3CommandTest)
|
|||||||
VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
|
VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testAUTH_InitialResponse()
|
||||||
|
{
|
||||||
|
vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism", "initial-response");
|
||||||
|
|
||||||
|
VASSERT_NOT_NULL("Not null", cmd);
|
||||||
|
VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
|
||||||
|
}
|
||||||
|
|
||||||
void testSTLS()
|
void testSTLS()
|
||||||
{
|
{
|
||||||
vmime::shared_ptr <POP3Command> cmd = POP3Command::STLS();
|
vmime::shared_ptr <POP3Command> cmd = POP3Command::STLS();
|
||||||
|
@ -37,6 +37,7 @@ VMIME_TEST_SUITE_BEGIN(SMTPCommandTest)
|
|||||||
VMIME_TEST(testHELO)
|
VMIME_TEST(testHELO)
|
||||||
VMIME_TEST(testEHLO)
|
VMIME_TEST(testEHLO)
|
||||||
VMIME_TEST(testAUTH)
|
VMIME_TEST(testAUTH)
|
||||||
|
VMIME_TEST(testAUTH_InitialResponse)
|
||||||
VMIME_TEST(testSTARTTLS)
|
VMIME_TEST(testSTARTTLS)
|
||||||
VMIME_TEST(testMAIL)
|
VMIME_TEST(testMAIL)
|
||||||
VMIME_TEST(testMAIL_Encoded)
|
VMIME_TEST(testMAIL_Encoded)
|
||||||
@ -95,6 +96,14 @@ VMIME_TEST_SUITE_BEGIN(SMTPCommandTest)
|
|||||||
VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
|
VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testAUTH_InitialResponse()
|
||||||
|
{
|
||||||
|
vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism", "initial-response");
|
||||||
|
|
||||||
|
VASSERT_NOT_NULL("Not null", cmd);
|
||||||
|
VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
|
||||||
|
}
|
||||||
|
|
||||||
void testSTARTTLS()
|
void testSTARTTLS()
|
||||||
{
|
{
|
||||||
vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::STARTTLS();
|
vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::STARTTLS();
|
||||||
|
Loading…
Reference in New Issue
Block a user