gardesk/garcard / 82d644f

Browse files

Test helper success and failure callbacks

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
82d644fa7b1fe165e859741e642dfd6032f4541c
Parents
e0d107c
Tree
25d929f

1 changed file

StatusFile+-
M garcard/src/polkit_helper.rs 115 6
garcard/src/polkit_helper.rsmodified
@@ -664,6 +664,8 @@ mod tests {
664664
         plain_response: PromptResponse,
665665
         infos: Vec<String>,
666666
         errors: Vec<String>,
667
+        success_count: usize,
668
+        failure_messages: Vec<String>,
667669
     }
668670
 
669671
     impl Default for FakePrompt {
@@ -673,6 +675,8 @@ mod tests {
673675
                 plain_response: PromptResponse::Canceled,
674676
                 infos: Vec::new(),
675677
                 errors: Vec::new(),
678
+                success_count: 0,
679
+                failure_messages: Vec::new(),
676680
             }
677681
         }
678682
     }
@@ -695,6 +699,16 @@ mod tests {
695699
             self.infos.push(message.to_string());
696700
             Ok(())
697701
         }
702
+
703
+        fn auth_succeeded(&mut self) -> Result<()> {
704
+            self.success_count += 1;
705
+            Ok(())
706
+        }
707
+
708
+        fn auth_failed(&mut self, message: &str) -> Result<()> {
709
+            self.failure_messages.push(message.to_string());
710
+            Ok(())
711
+        }
698712
     }
699713
 
700714
     fn temp_socket_path() -> PathBuf {
@@ -818,15 +832,15 @@ mod tests {
818832
         let client = HelperSocketClient::new(&socket_path);
819833
         let mut prompts = FakePrompt {
820834
             secret_response: PromptResponse::Submitted("correct horse".to_string()),
821
-            plain_response: PromptResponse::Canceled,
822
-            infos: Vec::new(),
823
-            errors: Vec::new(),
835
+            ..FakePrompt::default()
824836
         };
825837
 
826838
         let result = client
827839
             .authenticate("alice", "cookie-123", &mut prompts)
828840
             .expect("client auth");
829841
         assert_eq!(result, HelperOutcome::Authorized);
842
+        assert_eq!(prompts.success_count, 1);
843
+        assert!(prompts.failure_messages.is_empty());
830844
         server.join().expect("server join");
831845
 
832846
         let lines = transcript.lock().expect("lock transcript");
@@ -861,9 +875,7 @@ mod tests {
861875
         let client = HelperSocketClient::new(&socket_path);
862876
         let mut prompts = FakePrompt {
863877
             secret_response: PromptResponse::TimedOut,
864
-            plain_response: PromptResponse::Canceled,
865
-            infos: Vec::new(),
866
-            errors: Vec::new(),
878
+            ..FakePrompt::default()
867879
         };
868880
 
869881
         let outcome = client
@@ -875,6 +887,103 @@ mod tests {
875887
         let _ = std::fs::remove_file(&socket_path);
876888
     }
877889
 
890
+    #[test]
891
+    fn helper_client_reports_failure_callback_for_denied_attempt() {
892
+        let socket_path = temp_socket_path();
893
+        let listener = UnixListener::bind(&socket_path).expect("bind test socket");
894
+
895
+        let server = thread::spawn(move || {
896
+            let (mut stream, _) = listener.accept().expect("accept");
897
+            let read_stream = stream.try_clone().expect("clone");
898
+            let mut reader = BufReader::new(read_stream);
899
+
900
+            let mut first_line = String::new();
901
+            reader.read_line(&mut first_line).expect("read first line");
902
+            if first_line.trim() == "alice" {
903
+                let mut cookie = String::new();
904
+                reader.read_line(&mut cookie).expect("read cookie");
905
+            }
906
+
907
+            stream
908
+                .write_all(b"PAM_PROMPT_ECHO_OFF Password:\n")
909
+                .expect("write prompt");
910
+            stream.flush().expect("flush prompt");
911
+
912
+            let mut secret = String::new();
913
+            reader.read_line(&mut secret).expect("read secret");
914
+
915
+            stream.write_all(b"FAILURE\n").expect("write failure");
916
+            stream.flush().expect("flush failure");
917
+        });
918
+
919
+        let client = HelperSocketClient::new(&socket_path);
920
+        let mut prompts = FakePrompt {
921
+            secret_response: PromptResponse::Submitted("wrong horse".to_string()),
922
+            ..FakePrompt::default()
923
+        };
924
+
925
+        let outcome = client
926
+            .authenticate("alice", "cookie-failure", &mut prompts)
927
+            .expect("authenticate failure");
928
+        assert_eq!(outcome, HelperOutcome::Denied);
929
+        assert_eq!(prompts.success_count, 0);
930
+        assert_eq!(prompts.failure_messages, vec!["Authentication failed"]);
931
+
932
+        server.join().expect("server join");
933
+        let _ = std::fs::remove_file(&socket_path);
934
+    }
935
+
936
+    #[test]
937
+    fn helper_client_allows_success_after_diagnostic_error_line() {
938
+        let socket_path = temp_socket_path();
939
+        let listener = UnixListener::bind(&socket_path).expect("bind test socket");
940
+
941
+        let server = thread::spawn(move || {
942
+            let (mut stream, _) = listener.accept().expect("accept");
943
+            let read_stream = stream.try_clone().expect("clone");
944
+            let mut reader = BufReader::new(read_stream);
945
+
946
+            let mut first_line = String::new();
947
+            reader.read_line(&mut first_line).expect("read first line");
948
+            if first_line.trim() == "alice" {
949
+                let mut cookie = String::new();
950
+                reader.read_line(&mut cookie).expect("read cookie");
951
+            }
952
+
953
+            stream
954
+                .write_all(b"PAM_PROMPT_ECHO_OFF Password:\n")
955
+                .expect("write prompt");
956
+            stream.flush().expect("flush prompt");
957
+
958
+            let mut secret = String::new();
959
+            reader.read_line(&mut secret).expect("read secret");
960
+
961
+            stream
962
+                .write_all(b"PAM_ERROR_MSG previous attempt failed\n")
963
+                .expect("write helper diagnostic");
964
+            stream.flush().expect("flush helper diagnostic");
965
+            stream.write_all(b"SUCCESS\n").expect("write success");
966
+            stream.flush().expect("flush success");
967
+        });
968
+
969
+        let client = HelperSocketClient::new(&socket_path);
970
+        let mut prompts = FakePrompt {
971
+            secret_response: PromptResponse::Submitted("correct horse".to_string()),
972
+            ..FakePrompt::default()
973
+        };
974
+
975
+        let outcome = client
976
+            .authenticate("alice", "cookie-success", &mut prompts)
977
+            .expect("authenticate success");
978
+        assert_eq!(outcome, HelperOutcome::Authorized);
979
+        assert_eq!(prompts.success_count, 1);
980
+        assert!(prompts.failure_messages.is_empty());
981
+        assert_eq!(prompts.errors, vec!["previous attempt failed"]);
982
+
983
+        server.join().expect("server join");
984
+        let _ = std::fs::remove_file(&socket_path);
985
+    }
986
+
878987
     #[test]
879988
     fn scrub_string_clears_input() {
880989
         let mut value = "top-secret".to_string();