@ -22,6 +22,7 @@ __metaclass__ = type
import passlib
from passlib . handlers import pbkdf2
from units . mock . loader import DictDataLoader
from ansible . compat . tests import unittest
from ansible . compat . tests . mock import mock_open , patch
@ -29,11 +30,8 @@ from ansible.errors import AnsibleError
from ansible . module_utils . six import text_type
from ansible . module_utils . six . moves import builtins
from ansible . plugins import PluginLoader
from ansible . utils import encrypt
from units . mock . loader import DictDataLoader
from ansible . plugins . lookup import password
from ansible . utils import encrypt
DEFAULT_CHARS = sorted ( [ u ' ascii_letters ' , u ' digits ' , u " .,:-_ " ] )
@ -42,128 +40,149 @@ DEFAULT_CANDIDATE_CHARS = u'.,:-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU
# Currently there isn't a new-style
old_style_params_data = (
# Simple case
dict ( term = u ' /path/to/file ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/to/file ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
# Special characters in path
dict ( term = u ' /path/with/embedded spaces and/file ' ,
filename = u ' /path/with/embedded spaces and/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/with/equals/cn=com.ansible ' ,
filename = u ' /path/with/equals/cn=com.ansible ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/with/unicode/くらとみ/file ' ,
filename = u ' /path/with/unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/embedded spaces and/file ' ,
filename = u ' /path/with/embedded spaces and/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/equals/cn=com.ansible ' ,
filename = u ' /path/with/equals/cn=com.ansible ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/unicode/くらとみ/file ' ,
filename = u ' /path/with/unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
# Mix several special chars
dict ( term = u ' /path/with/utf 8 and spaces/くらとみ/file ' ,
filename = u ' /path/with/utf 8 and spaces/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/with/encoding=unicode/くらとみ/file ' ,
filename = u ' /path/with/encoding=unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/with/encoding=unicode/くらとみ/and spaces file ' ,
filename = u ' /path/with/encoding=unicode/くらとみ/and spaces file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/utf 8 and spaces/くらとみ/file ' ,
filename = u ' /path/with/utf 8 and spaces/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/encoding=unicode/くらとみ/file ' ,
filename = u ' /path/with/encoding=unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/with/encoding=unicode/くらとみ/and spaces file ' ,
filename = u ' /path/with/encoding=unicode/くらとみ/and spaces file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
# Simple parameters
dict ( term = u ' /path/to/file length=42 ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = 42 , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/to/file encrypt=pbkdf2_sha256 ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = ' pbkdf2_sha256 ' , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict ( term = u ' /path/to/file chars=abcdefghijklmnop ' ,
dict (
term = u ' /path/to/file length=42 ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = 42 , encrypt = None , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/to/file encrypt=pbkdf2_sha256 ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = ' pbkdf2_sha256 ' , chars = DEFAULT_CHARS ) ,
candidate_chars = DEFAULT_CANDIDATE_CHARS ,
) ,
dict (
term = u ' /path/to/file chars=abcdefghijklmnop ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' abcdefghijklmnop ' ] ) ,
candidate_chars = u ' abcdefghijklmnop ' ,
) ,
dict ( term = u ' /path/to/file chars=digits,abc,def ' ,
) ,
dict (
term = u ' /path/to/file chars=digits,abc,def ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' abc ' , u ' def ' ] ) ) ,
candidate_chars = u ' abcdef0123456789 ' ,
) ,
) ,
# Including comma in chars
dict ( term = u ' /path/to/file chars=abcdefghijklmnop,,digits ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' abcdefghijklmnop ' , u ' , ' , u ' digits ' ] ) ) ,
candidate_chars = u ' ,abcdefghijklmnop0123456789 ' ,
) ,
dict ( term = u ' /path/to/file chars=,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' , ' ] ) ,
candidate_chars = u ' , ' ,
) ,
dict (
term = u ' /path/to/file chars=abcdefghijklmnop,,digits ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' abcdefghijklmnop ' , u ' , ' , u ' digits ' ] ) ) ,
candidate_chars = u ' ,abcdefghijklmnop0123456789 ' ,
) ,
dict (
term = u ' /path/to/file chars=,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' , ' ] ) ,
candidate_chars = u ' , ' ,
) ,
# Including = in chars
dict ( term = u ' /path/to/file chars=digits,=,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' = ' , u ' , ' ] ) ) ,
candidate_chars = u ' ,=0123456789 ' ,
) ,
dict ( term = u ' /path/to/file chars=digits,abc=def ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' abc=def ' ] ) ) ,
candidate_chars = u ' abc=def0123456789 ' ,
) ,
dict (
term = u ' /path/to/file chars=digits,=,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' = ' , u ' , ' ] ) ) ,
candidate_chars = u ' ,=0123456789 ' ,
) ,
dict (
term = u ' /path/to/file chars=digits,abc=def ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' abc=def ' ] ) ) ,
candidate_chars = u ' abc=def0123456789 ' ,
) ,
# Including unicode in chars
dict ( term = u ' /path/to/file chars=digits,くらとみ,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' くらとみ ' , u ' , ' ] ) ) ,
candidate_chars = u ' ,0123456789くらとみ ' ,
) ,
dict (
term = u ' /path/to/file chars=digits,くらとみ,, ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' digits ' , u ' くらとみ ' , u ' , ' ] ) ) ,
candidate_chars = u ' ,0123456789くらとみ ' ,
) ,
# Including only unicode in chars
dict ( term = u ' /path/to/file chars=くらとみ ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' くらとみ ' ] ) ) ,
candidate_chars = u ' くらとみ ' ,
) ,
dict (
term = u ' /path/to/file chars=くらとみ ' ,
filename = u ' /path/to/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' くらとみ ' ] ) ) ,
candidate_chars = u ' くらとみ ' ,
) ,
# Include ':' in path
dict ( term = u ' /path/to/file_with:colon chars=ascii_letters,digits ' ,
filename = u ' /path/to/file_with:colon ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' ascii_letters ' , u ' digits ' ] ) ) ,
candidate_chars = u ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ' ,
) ,
dict (
term = u ' /path/to/file_with:colon chars=ascii_letters,digits ' ,
filename = u ' /path/to/file_with:colon ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = sorted ( [ u ' ascii_letters ' , u ' digits ' ] ) ) ,
candidate_chars = u ' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ' ,
) ,
# Including special chars in both path and chars
# Special characters in path
dict ( term = u ' /path/with/embedded spaces and/file chars=abc=def ' ,
filename = u ' /path/with/embedded spaces and/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' abc=def ' ] ) ,
candidate_chars = u ' abc=def ' ,
) ,
dict ( term = u ' /path/with/equals/cn=com.ansible chars=abc=def ' ,
filename = u ' /path/with/equals/cn=com.ansible ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' abc=def ' ] ) ,
candidate_chars = u ' abc=def ' ,
) ,
dict ( term = u ' /path/with/unicode/くらとみ/file chars=くらとみ ' ,
filename = u ' /path/with/unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' くらとみ ' ] ) ,
candidate_chars = u ' くらとみ ' ,
) ,
dict (
term = u ' /path/with/embedded spaces and/file chars=abc=def ' ,
filename = u ' /path/with/embedded spaces and/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' abc=def ' ] ) ,
candidate_chars = u ' abc=def ' ,
) ,
dict (
term = u ' /path/with/equals/cn=com.ansible chars=abc=def ' ,
filename = u ' /path/with/equals/cn=com.ansible ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' abc=def ' ] ) ,
candidate_chars = u ' abc=def ' ,
) ,
dict (
term = u ' /path/with/unicode/くらとみ/file chars=くらとみ ' ,
filename = u ' /path/with/unicode/くらとみ/file ' ,
params = dict ( length = password . DEFAULT_LENGTH , encrypt = None , chars = [ u ' くらとみ ' ] ) ,
candidate_chars = u ' くらとみ ' ,
) ,
)
@ -306,27 +325,26 @@ class TestFormatContent(unittest.TestCase):
def test_no_encrypt ( self ) :
self . assertEqual (
password . _format_content ( password = u ' hunter42 ' ,
salt = u ' 87654321 ' ,
encrypt = False ) ,
salt = u ' 87654321 ' ,
encrypt = False ) ,
u ' hunter42 salt=87654321 ' )
def test_no_encrypt_no_salt ( self ) :
self . assertEqual (
password . _format_content ( password = u ' hunter42 ' ,
salt = None ,
encrypt = False ) ,
salt = None ,
encrypt = False ) ,
u ' hunter42 ' )
def test_encrypt ( self ) :
self . assertEqual (
password . _format_content ( password = u ' hunter42 ' ,
salt = u ' 87654321 ' ,
encrypt = ' pbkdf2_sha256 ' ) ,
salt = u ' 87654321 ' ,
encrypt = ' pbkdf2_sha256 ' ) ,
u ' hunter42 salt=87654321 ' )
def test_encrypt_no_salt ( self ) :
self . assertRaises ( AssertionError , password . _format_content ,
u ' hunter42 ' , None , ' pbkdf2_sha256 ' )
self . assertRaises ( AssertionError , password . _format_content , u ' hunter42 ' , None , ' pbkdf2_sha256 ' )
class TestWritePasswordFile ( unittest . TestCase ) :
@ -351,13 +369,13 @@ class TestWritePasswordFile(unittest.TestCase):
class TestLookupModule ( unittest . TestCase ) :
def setUp ( self ) :
self . fake_loader = DictDataLoader ( { ' /path/to/somewhere ' : ' sdfsdf ' } )
self . fake_loader = DictDataLoader ( { ' /path/to/somewhere ' : ' sdfsdf ' } )
self . password_lookup = password . LookupModule ( loader = self . fake_loader )
self . os_path_exists = password . os . path . exists
# Different releases of passlib default to a different number of rounds
self . sha256 = passlib . registry . get_crypt_handler ( ' pbkdf2_sha256 ' )
sha256_for_tests = pbkdf2 . create_pbkdf2_hash ( " sha256 " , 32 , 20000 )
sha256_for_tests = pbkdf2 . create_pbkdf2_hash ( " sha256 " , 32 , 20000 )
passlib . registry . register_crypt_handler ( sha256_for_tests , force = True )
def tearDown ( self ) :
@ -369,8 +387,7 @@ class TestLookupModule(unittest.TestCase):
def test_no_encrypt ( self , mock_get_paths , mock_write_file ) :
mock_get_paths . return_value = [ ' /path/one ' , ' /path/two ' , ' /path/three ' ]
results = self . password_lookup . run ( [ u ' /path/to/somewhere ' ] ,
None )
results = self . password_lookup . run ( [ u ' /path/to/somewhere ' ] , None )
# FIXME: assert something useful
for result in results :
@ -382,8 +399,7 @@ class TestLookupModule(unittest.TestCase):
def test_encrypt ( self , mock_get_paths , mock_write_file ) :
mock_get_paths . return_value = [ ' /path/one ' , ' /path/two ' , ' /path/three ' ]
results = self . password_lookup . run ( [ u ' /path/to/somewhere encrypt=pbkdf2_sha256 ' ] ,
None )
results = self . password_lookup . run ( [ u ' /path/to/somewhere encrypt=pbkdf2_sha256 ' ] , None )
# pbkdf2 format plus hash
expected_password_length = 76
@ -412,8 +428,7 @@ class TestLookupModule(unittest.TestCase):
password . os . path . exists = lambda x : True
with patch . object ( builtins , ' open ' , mock_open ( read_data = b ' hunter42 salt=87654321 \n ' ) ) as m :
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=anything encrypt=pbkdf2_sha256 ' ] ,
None )
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=anything encrypt=pbkdf2_sha256 ' ] , None )
for result in results :
self . assertEqual ( result , u ' $pbkdf2-sha256$20000$ODc2NTQzMjE$Uikde0cv0BKaRaAXMrUQB.zvG4GmnjClwjghwIRf2gU ' )
@ -424,8 +439,7 @@ class TestLookupModule(unittest.TestCase):
password . os . path . exists = lambda x : True
with patch . object ( builtins , ' open ' , mock_open ( read_data = b ' hunter42 salt=87654321 \n ' ) ) as m :
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=anything ' ] ,
None )
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=anything ' ] , None )
for result in results :
self . assertEqual ( result , u ' hunter42 ' )
@ -435,7 +449,6 @@ class TestLookupModule(unittest.TestCase):
def test_only_a ( self , mock_get_paths , mock_write_file ) :
mock_get_paths . return_value = [ ' /path/one ' , ' /path/two ' , ' /path/three ' ]
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=a ' ] ,
None )
results = self . password_lookup . run ( [ u ' /path/to/somewhere chars=a ' ] , None )
for result in results :
self . assertEquals ( result , u ' a ' * password . DEFAULT_LENGTH )