1# Copyright (C) 2009 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#    * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9#    * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13#    * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import os
30import tempfile
31import unittest
32from webkitpy.credentials import Credentials
33from webkitpy.executive import Executive
34from webkitpy.outputcapture import OutputCapture
35from webkitpy.mock import Mock
36
37class CredentialsTest(unittest.TestCase):
38    example_security_output = """keychain: "/Users/test/Library/Keychains/login.keychain"
39class: "inet"
40attributes:
41    0x00000007 <blob>="bugs.webkit.org (test@webkit.org)"
42    0x00000008 <blob>=<NULL>
43    "acct"<blob>="test@webkit.org"
44    "atyp"<blob>="form"
45    "cdat"<timedate>=0x32303039303832353233353231365A00  "20090825235216Z\000"
46    "crtr"<uint32>=<NULL>
47    "cusi"<sint32>=<NULL>
48    "desc"<blob>="Web form password"
49    "icmt"<blob>="default"
50    "invi"<sint32>=<NULL>
51    "mdat"<timedate>=0x32303039303930393137323635315A00  "20090909172651Z\000"
52    "nega"<sint32>=<NULL>
53    "path"<blob>=<NULL>
54    "port"<uint32>=0x00000000
55    "prot"<blob>=<NULL>
56    "ptcl"<uint32>="htps"
57    "scrp"<sint32>=<NULL>
58    "sdmn"<blob>=<NULL>
59    "srvr"<blob>="bugs.webkit.org"
60    "type"<uint32>=<NULL>
61password: "SECRETSAUCE"
62"""
63
64    def test_keychain_lookup_on_non_mac(self):
65        class FakeCredentials(Credentials):
66            def _is_mac_os_x(self):
67                return False
68        credentials = FakeCredentials("bugs.webkit.org")
69        self.assertEqual(credentials._is_mac_os_x(), False)
70        self.assertEqual(credentials._credentials_from_keychain("foo"), ["foo", None])
71
72    def test_security_output_parse(self):
73        credentials = Credentials("bugs.webkit.org")
74        self.assertEqual(credentials._parse_security_tool_output(self.example_security_output), ["test@webkit.org", "SECRETSAUCE"])
75
76    def test_security_output_parse_entry_not_found(self):
77        credentials = Credentials("foo.example.com")
78        if not credentials._is_mac_os_x():
79            return # This test does not run on a non-Mac.
80
81        # Note, we ignore the captured output because it is already covered
82        # by the test case CredentialsTest._assert_security_call (below).
83        outputCapture = OutputCapture()
84        outputCapture.capture_output()
85        self.assertEqual(credentials._run_security_tool(), None)
86        outputCapture.restore_output()
87
88    def _assert_security_call(self, username=None):
89        executive_mock = Mock()
90        credentials = Credentials("example.com", executive=executive_mock)
91
92        expected_stderr = "Reading Keychain for example.com account and password.  Click \"Allow\" to continue...\n"
93        OutputCapture().assert_outputs(self, credentials._run_security_tool, [username], expected_stderr=expected_stderr)
94
95        security_args = ["/usr/bin/security", "find-internet-password", "-g", "-s", "example.com"]
96        if username:
97            security_args += ["-a", username]
98        executive_mock.run_command.assert_called_with(security_args)
99
100    def test_security_calls(self):
101        self._assert_security_call()
102        self._assert_security_call(username="foo")
103
104    def test_git_config_calls(self):
105        executive_mock = Mock()
106        credentials = Credentials("example.com", executive=executive_mock)
107        credentials._read_git_config("foo")
108        executive_mock.run_command.assert_called_with(["git", "config", "--get", "foo"], error_handler=Executive.ignore_error)
109
110        credentials = Credentials("example.com", git_prefix="test_prefix", executive=executive_mock)
111        credentials._read_git_config("foo")
112        executive_mock.run_command.assert_called_with(["git", "config", "--get", "test_prefix.foo"], error_handler=Executive.ignore_error)
113
114    def test_read_credentials_without_git_repo(self):
115        class FakeCredentials(Credentials):
116            def _is_mac_os_x(self):
117                return True
118            def _credentials_from_keychain(self, username):
119                return ["test@webkit.org", "SECRETSAUCE"]
120
121        temp_dir_path = tempfile.mkdtemp(suffix="not_a_git_repo")
122        credentials = FakeCredentials("bugs.webkit.org", cwd=temp_dir_path)
123        self.assertEqual(credentials.read_credentials(), ["test@webkit.org", "SECRETSAUCE"])
124        os.rmdir(temp_dir_path)
125
126if __name__ == '__main__':
127    unittest.main()
128