OSX install broken when using virtualenvs?

masklinn avatarmasklinn created an issue

This lib seemed way interesting and got a bit of publicity a few weeks ago, so I decided to check it out the usual way: create a virtualenv, pip install the library inside it and play around.

Except I didn't get anywhere: get_password would always return None (with no keychain prompt) and set_password would throw OSError: Can't store password in Keychain, in both cases whatever the service & account are. After a few reinstallations, I tried compiling from scratch (cloning from mercurial and python setup.py build… success. Both tip (4a551eda6bf8) and tag 0.2 build and work perfectly.

Try to python setup.py install it in my virtualenv, failure again (except it now throws keyring.backend.PasswordSetError on set_password, due to being tip I guess).

Tested the same scenario in a fresh OpenSUSE image, no issue.

Comments (16)

  1. Jonathan Ballet

    Masklinn or someone with OS X: is this issue still valid with current trunk?

    Many things has changed on the OS X side (we no longer ship C extensions, we rely on ctypes instead). I'll be glad to help, but I don't have access to any OS X machine ATM.

  2. Chris Adams

    This behaviour is unchanged with 0.7 for any attempt to set a password:

    >>> keyring.backends.osx_keychain.password_set("foo", "bar", "baaz")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/cadams/.virtualenvs/wdl/lib/python2.7/site-packages/keyring/backends/osx_keychain.py", line 106, in password_set
        raise OSError("Can't store password in keychain")
    OSError: Can't store password in keychain
    

    It's not clear that this is specific to a virtualenv - if I get more time I'll compare it against my code (https://github.com/acdha/pymacadmin/blob/master/lib/PyMacAdmin/Security/Keychain.py) — if nothing else it'd be nice to report the underlying API status value rather than squashing it down to a generic failure.

  3. Dan Sully

    Same issue for me with 0.7.1 on Lion under a virtualenv.

    The actual status error is:

    (error -67061: "code or signature modified")

    Which I believe means that the Python code doesn't have rights to the keychain.

  4. Jonathan Ballet
    • changed status to open

    Hey Chris,

    could you provide a patch or branch with this method so that potentially interested users can try it? It should fit into the existing tests, ideally!

    Thanks :)

  5. Jake Basile

    And of course I forget to attach the errors.

    ======================================================================
    FAIL: test_difficult_chars (__main__.OSXKeychainTestCase)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "keyring/tests/test_backend.py", line 182, in test_difficult_chars
        self.check_set_get(service, username, password)
      File "keyring/tests/test_backend.py", line 166, in check_set_get
        self.assertEqual(keyring.get_password(service, username), password)
    AssertionError: '' != "-\r@\t<_$`_; =-#>['/?\x0c"
    
    ----------------------------------------------------------------------
    Ran 31 tests in 1.033s
    

    It's not storing or retrieving the fancy characters correctly. I tried surrounding the argument with quotes, but python is apparently already doing that, because then I'll get "'password'" back.

    I've tried escaping the usernames/passwords/realms with the following function, but it still fails that test.

    def escape_chars(s):
        print s
        s = s.replace('|', '\|')
        s = s.replace('&', '\&')
        s = s.replace(';', '\;')
        s = s.replace('<', '\<')
        s = s.replace('>', '\>')
        s = s.replace('(', '\(')
        s = s.replace(')', '\)')
        s = s.replace('$', '\$')
        s = s.replace('`', '\`')
        s = s.replace('\\', '\\\\')
        s = s.replace('"', '\"')
        s = s.replace('\'', '\\\'')
        s = s.replace(' ', '\ ')
        s = s.replace('\t', '\\\t')
        s = s.replace('\n', '\\\n')
        return s
    
  6. Jake Basile

    I fixed the failing test.

    The issue is that the security command formats odd characters in a way I wasn't expecting. If and when it encounters certain chars, it also outputs the entire password as a hex encoded string as well. I was able to look for the hex string, and if it's there decode and return it instead of the oddly formed password string.

    Do I need to port this back to 2.6?

  7. Jonathan Ballet

    Wow, Python 2.4+ oO ... OK, anyway, without subprocess.check_output(), it should be compatible now.

    I don't have an OS X machine to test this fix though, I would like at least one other person which is affected by #13 to try Jake's branch and report here if:

    • it indeed fixes the problem of #13 ;
    • all the tests still pass ;

    If so, I don't see any reason not to merge his work.

    Thanks Jake!

  8. Log in to comment
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.