Home | History | Annotate | Download | only in net
      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 
     29 from __future__ import with_statement
     30 
     31 import os
     32 import tempfile
     33 import unittest
     34 from webkitpy.common.net.credentials import Credentials
     35 from webkitpy.common.system.executive import Executive
     36 from webkitpy.common.system.outputcapture import OutputCapture
     37 from webkitpy.thirdparty.mock import Mock
     38 
     39 
     40 # FIXME: Other unit tests probably want this class.
     41 class _TemporaryDirectory(object):
     42     def __init__(self, **kwargs):
     43         self._kwargs = kwargs
     44         self._directory_path = None
     45 
     46     def __enter__(self):
     47         self._directory_path = tempfile.mkdtemp(**self._kwargs)
     48         return self._directory_path
     49 
     50     def __exit__(self, type, value, traceback):
     51         os.rmdir(self._directory_path)
     52 
     53 
     54 class CredentialsTest(unittest.TestCase):
     55     example_security_output = """keychain: "/Users/test/Library/Keychains/login.keychain"
     56 class: "inet"
     57 attributes:
     58     0x00000007 <blob>="bugs.webkit.org (test@webkit.org)"
     59     0x00000008 <blob>=<NULL>
     60     "acct"<blob>="test@webkit.org"
     61     "atyp"<blob>="form"
     62     "cdat"<timedate>=0x32303039303832353233353231365A00  "20090825235216Z\000"
     63     "crtr"<uint32>=<NULL>
     64     "cusi"<sint32>=<NULL>
     65     "desc"<blob>="Web form password"
     66     "icmt"<blob>="default"
     67     "invi"<sint32>=<NULL>
     68     "mdat"<timedate>=0x32303039303930393137323635315A00  "20090909172651Z\000"
     69     "nega"<sint32>=<NULL>
     70     "path"<blob>=<NULL>
     71     "port"<uint32>=0x00000000 
     72     "prot"<blob>=<NULL>
     73     "ptcl"<uint32>="htps"
     74     "scrp"<sint32>=<NULL>
     75     "sdmn"<blob>=<NULL>
     76     "srvr"<blob>="bugs.webkit.org"
     77     "type"<uint32>=<NULL>
     78 password: "SECRETSAUCE"
     79 """
     80 
     81     def test_keychain_lookup_on_non_mac(self):
     82         class FakeCredentials(Credentials):
     83             def _is_mac_os_x(self):
     84                 return False
     85         credentials = FakeCredentials("bugs.webkit.org")
     86         self.assertEqual(credentials._is_mac_os_x(), False)
     87         self.assertEqual(credentials._credentials_from_keychain("foo"), ["foo", None])
     88 
     89     def test_security_output_parse(self):
     90         credentials = Credentials("bugs.webkit.org")
     91         self.assertEqual(credentials._parse_security_tool_output(self.example_security_output), ["test (at] webkit.org", "SECRETSAUCE"])
     92 
     93     def test_security_output_parse_entry_not_found(self):
     94         credentials = Credentials("foo.example.com")
     95         if not credentials._is_mac_os_x():
     96             return # This test does not run on a non-Mac.
     97 
     98         # Note, we ignore the captured output because it is already covered
     99         # by the test case CredentialsTest._assert_security_call (below).
    100         outputCapture = OutputCapture()
    101         outputCapture.capture_output()
    102         self.assertEqual(credentials._run_security_tool(), None)
    103         outputCapture.restore_output()
    104 
    105     def _assert_security_call(self, username=None):
    106         executive_mock = Mock()
    107         credentials = Credentials("example.com", executive=executive_mock)
    108 
    109         expected_stderr = "Reading Keychain for example.com account and password.  Click \"Allow\" to continue...\n"
    110         OutputCapture().assert_outputs(self, credentials._run_security_tool, [username], expected_stderr=expected_stderr)
    111 
    112         security_args = ["/usr/bin/security", "find-internet-password", "-g", "-s", "example.com"]
    113         if username:
    114             security_args += ["-a", username]
    115         executive_mock.run_command.assert_called_with(security_args)
    116 
    117     def test_security_calls(self):
    118         self._assert_security_call()
    119         self._assert_security_call(username="foo")
    120 
    121     def test_credentials_from_environment(self):
    122         executive_mock = Mock()
    123         credentials = Credentials("example.com", executive=executive_mock)
    124 
    125         saved_environ = os.environ.copy()
    126         os.environ['WEBKIT_BUGZILLA_USERNAME'] = "foo"
    127         os.environ['WEBKIT_BUGZILLA_PASSWORD'] = "bar"
    128         username, password = credentials._credentials_from_environment()
    129         self.assertEquals(username, "foo")
    130         self.assertEquals(password, "bar")
    131         os.environ = saved_environ
    132 
    133     def test_read_credentials_without_git_repo(self):
    134         # FIXME: This should share more code with test_keyring_without_git_repo
    135         class FakeCredentials(Credentials):
    136             def _is_mac_os_x(self):
    137                 return True
    138 
    139             def _credentials_from_keychain(self, username):
    140                 return ("test (at] webkit.org", "SECRETSAUCE")
    141 
    142             def _credentials_from_environment(self):
    143                 return (None, None)
    144 
    145         with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
    146             credentials = FakeCredentials("bugs.webkit.org", cwd=temp_dir_path)
    147             # FIXME: Using read_credentials here seems too broad as higher-priority
    148             # credential source could be affected by the user's environment.
    149             self.assertEqual(credentials.read_credentials(), ("test (at] webkit.org", "SECRETSAUCE"))
    150 
    151 
    152     def test_keyring_without_git_repo(self):
    153         # FIXME: This should share more code with test_read_credentials_without_git_repo
    154         class MockKeyring(object):
    155             def get_password(self, host, username):
    156                 return "NOMNOMNOM"
    157 
    158         class FakeCredentials(Credentials):
    159             def _is_mac_os_x(self):
    160                 return True
    161 
    162             def _credentials_from_keychain(self, username):
    163                 return ("test (at] webkit.org", None)
    164 
    165             def _credentials_from_environment(self):
    166                 return (None, None)
    167 
    168         with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
    169             credentials = FakeCredentials("fake.hostname", cwd=temp_dir_path, keyring=MockKeyring())
    170             # FIXME: Using read_credentials here seems too broad as higher-priority
    171             # credential source could be affected by the user's environment.
    172             self.assertEqual(credentials.read_credentials(), ("test (at] webkit.org", "NOMNOMNOM"))
    173 
    174 
    175 if __name__ == '__main__':
    176     unittest.main()
    177