git.fiddlerwoaroof.com
conversation_test.cc
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();
 }