01c00cfe |
#include <vector>
#include <algorithm>
#include <string>
|
0b6e39a6 |
#include <security/pam_modules.h>
#include "conversation.h"
#include "test_util.h"
|
01c00cfe |
#include "pam.h"
|
0b6e39a6 |
|
cdf7fd74 |
class fake_pam_conversation : public pam_conversation
{
private:
pam_response response_;
std::string answer_;
public:
|
b017a4d2 |
fake_pam_conversation (const std::string &answer) : answer_ (answer) {}
int conv (const std::vector<const struct pam_message *> &prompts,
std::vector<struct pam_response *> &answers)
|
cdf7fd74 |
{
if (prompts.size() != 1) {
|
b017a4d2 |
throw std::string ("test only supports one prompt");
|
01c00cfe |
}
|
b017a4d2 |
|
cdf7fd74 |
response_.resp_retcode = 0;
|
b017a4d2 |
response_.resp = const_cast<char *> (answer_.c_str());
answers.resize (1);
|
cdf7fd74 |
answers[0] = &response_;
return 0;
}
|
01c00cfe |
};
|
cdf7fd74 |
class fake_failing_conversation: public pam_conversation
{
|
1bbd05bc |
|
cdf7fd74 |
public:
|
b017a4d2 |
int conv (const std::vector<const struct pam_message *> &prompts,
std::vector<struct pam_response *> &answers)
|
cdf7fd74 |
{
return 1;
}
|
1bbd05bc |
};
|
cdf7fd74 |
class fake_failing_answer_conversation: public pam_conversation
{
private:
pam_response response_;
std::string answer_;
public:
|
b017a4d2 |
fake_failing_answer_conversation() : answer_ ("ok:1") {}
int conv (const std::vector<const struct pam_message *> &prompts,
std::vector<struct pam_response *> &answers)
|
cdf7fd74 |
{
if (prompts.size() != 1) {
|
b017a4d2 |
throw std::string ("test only supports one prompt");
|
12570d65 |
}
|
b017a4d2 |
|
cdf7fd74 |
response_.resp_retcode = 13;
|
b017a4d2 |
response_.resp = const_cast<char *> (answer_.c_str());
answers.resize (1);
|
cdf7fd74 |
answers[0] = &response_;
return 0;
}
|
12570d65 |
};
|
cdf7fd74 |
class match_prompt_text_conversation : public pam_conversation
{
private:
pam_response response_;
std::string answer_;
std::string prompt_;
public:
|
b017a4d2 |
match_prompt_text_conversation (const std::string &prompt) : prompt_
(prompt), answer_ ("ok:123") {}
int conv (const std::vector<const struct pam_message *> &prompts,
std::vector<struct pam_response *> &answers)
|
cdf7fd74 |
{
if (prompt_ != prompts[0]->msg) {
|
b017a4d2 |
throw std::string ("prompt does not match");
|
f9c4622b |
}
|
b017a4d2 |
|
cdf7fd74 |
response_.resp_retcode = 0;
|
b017a4d2 |
response_.resp = const_cast<char *> (answer_.c_str());
answers.resize (1);
|
cdf7fd74 |
answers[0] = &response_;
return 0;
}
|
f9c4622b |
};
|
cdf7fd74 |
class match_prompt_style_conversation : public pam_conversation
{
private:
pam_response response_;
std::string answer_;
int style_;
public:
|
b017a4d2 |
match_prompt_style_conversation (int style) : style_ (style),
answer_ ("ok:123") {}
int conv (const std::vector<const struct pam_message *> &prompts,
std::vector<struct pam_response *> &answers)
|
cdf7fd74 |
{
if (style_ != prompts[0]->msg_style) {
|
b017a4d2 |
throw std::string ("style does not match");
|
c9d7e817 |
}
|
b017a4d2 |
|
cdf7fd74 |
response_.resp_retcode = 0;
|
b017a4d2 |
response_.resp = const_cast<char *> (answer_.c_str());
answers.resize (1);
|
cdf7fd74 |
answers[0] = &response_;
return 0;
}
|
c9d7e817 |
};
|
cdf7fd74 |
class fake_pam : public pam
{
private:
std::shared_ptr<pam_conversation> conversation_;
public:
|
b017a4d2 |
fake_pam (std::shared_ptr<pam_conversation> conversation) : conversation_
(conversation) {}
|
cdf7fd74 |
fake_pam() {}
|
b017a4d2 |
int get_conversation (pam_handle_t *pamh,
std::shared_ptr<pam_conversation> &conversation)
|
cdf7fd74 |
{
if (conversation_) {
conversation = conversation_;
return 0;
|
01c00cfe |
}
|
b017a4d2 |
|
cdf7fd74 |
return 12;
}
|
01c00cfe |
};
|
cdf7fd74 |
int returns_correct_token()
{
|
0b6e39a6 |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation ("user:code");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
0b6e39a6 |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
0b6e39a6 |
//then
|
b017a4d2 |
check (conversation.token() == "code", "returned incorrect token");
|
0b6e39a6 |
succeed();
}
|
cdf7fd74 |
int returns_correct_user_name()
{
|
be7b0e04 |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation ("sally:token");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
9e6b6179 |
|
be7b0e04 |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
be7b0e04 |
//then
|
b017a4d2 |
check (conversation.user_name() == "sally", "returned incorrect user name");
|
be7b0e04 |
succeed();
}
|
cdf7fd74 |
int returns_empty_user_and_token_when_no_colon()
{
|
24888e2d |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation ("sally");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
24888e2d |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
0b6e39a6 |
|
24888e2d |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
24888e2d |
succeed();
}
|
0b6e39a6 |
|
cdf7fd74 |
int returns_empty_user_and_token_when_empty_answer()
{
|
26830ef5 |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation ("");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
26830ef5 |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
26830ef5 |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
26830ef5 |
succeed();
}
|
cdf7fd74 |
int returns_empty_token_when_colon_end()
{
|
231e2d6e |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation ("sally:");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
231e2d6e |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
231e2d6e |
//then
|
b017a4d2 |
check (conversation.user_name() == "sally",
"did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
231e2d6e |
succeed();
}
|
cdf7fd74 |
int returns_empty_user_when_colon_begin()
{
|
231e2d6e |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_pam_conversation (":token");
pam_p pam = (pam_p)new fake_pam (fake_conversation);
|
231e2d6e |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
231e2d6e |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "token", "did not return empty token");
|
231e2d6e |
succeed();
}
|
cdf7fd74 |
int returns_empty_user_and_token_when_pam_cant_create_conversation()
{
|
662f2d36 |
// given
pam_handle_t *pamh;
pam_p pam = (pam_p)new fake_pam;
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
662f2d36 |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
662f2d36 |
succeed();
}
|
cdf7fd74 |
int prompts_user_with_correct_text()
{
|
f9c4622b |
// given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p match_conversation = (pam_conversation_p) new
match_prompt_text_conversation ("Dual control token: ");
pam_p pam = (pam_p)new fake_pam (match_conversation);
|
f9c4622b |
// when / then
try {
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
cdf7fd74 |
succeed();
|
f9c4622b |
} catch (const std::string &x) {
fail();
}
|
c9d7e817 |
}
|
cdf7fd74 |
int prompts_user_with_correct_style()
{
|
c9d7e817 |
// given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p match_conversation = (pam_conversation_p) new
match_prompt_style_conversation (PAM_PROMPT_ECHO_OFF);
pam_p pam = (pam_p)new fake_pam (match_conversation);
|
f9c4622b |
|
c9d7e817 |
// when / then
try {
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
cdf7fd74 |
succeed();
|
c9d7e817 |
} catch (const std::string &x) {
fail();
}
|
f9c4622b |
}
|
231e2d6e |
|
cdf7fd74 |
int returns_empty_user_and_token_when_conversation_fails()
{
|
1bbd05bc |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_failing_conversation;
pam_p pam = (pam_p) new fake_pam (fake_conversation);
|
1bbd05bc |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
c9d7e817 |
|
1bbd05bc |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
1bbd05bc |
succeed();
}
|
c9d7e817 |
|
cdf7fd74 |
int returns_empty_user_and_token_when_conversation_answer_fails()
{
|
12570d65 |
//given
pam_handle_t *pamh;
|
b017a4d2 |
pam_conversation_p fake_conversation = (pam_conversation_p) new
fake_failing_answer_conversation;
pam_p pam = (pam_p) new fake_pam (fake_conversation);
|
12570d65 |
//when
|
b017a4d2 |
pam_token_conversation conversation (pamh, pam);
|
12570d65 |
//then
|
b017a4d2 |
check (conversation.user_name() == "", "did not return empty user name");
check (conversation.token() == "", "did not return empty token");
|
12570d65 |
succeed();
}
|
c9d7e817 |
|
0b6e39a6 |
RESET_VARS_START
RESET_VARS_END
|
cdf7fd74 |
int run_tests()
{
|
b017a4d2 |
test (returns_correct_token);
test (returns_correct_user_name);
test (returns_empty_user_and_token_when_no_colon);
test (returns_empty_token_when_colon_end);
test (returns_empty_user_when_colon_begin);
test (returns_empty_user_and_token_when_empty_answer);
test (returns_empty_user_and_token_when_pam_cant_create_conversation);
test (prompts_user_with_correct_text);
test (prompts_user_with_correct_style);
test (returns_empty_user_and_token_when_conversation_fails);
test (returns_empty_user_and_token_when_conversation_answer_fails);
|
0b6e39a6 |
succeed();
}
|
b017a4d2 |
int main (int argc, char *args[])
|
cdf7fd74 |
{
|
0b6e39a6 |
return !run_tests();
}
|