Add support for crypted passwords to password lookup

Added new parameter 'encrypt' with same semantics from that of
vars_prompt. When encryption is requested a random salt will be
generated and stored along the password in the form:
'<password> salt=<salt>'.

Also store passwords with an ending '\n' for easier looking at files
with console tools. File content was being already rstripped so this
is harmless.
This commit is contained in:
Maykel Moya 2013-05-16 03:27:30 +02:00
parent c0f138db1f
commit 96afc3f462
2 changed files with 71 additions and 14 deletions

View file

@ -537,6 +537,15 @@ This length can be changed by passing an extra parameter::
target=/tmp/{{ client }}_{{ tier }}_{{ role }}_backup.sql
with_password: credentials/{{ client }}/{{ tier }}/{{ role }}/mysqlpassword length=15
(...)
# create an user with a given password
- user: name=guestuser
state=present
uid=5000
password={{ item }}
with_password: credentials/{{ hostname }}/userpassword encrypt=sha256_crypt
Setting the Environment (and Working With Proxies)
``````````````````````````````````````````````````

View file

@ -1,5 +1,6 @@
# (c) 2012, Daniel Hokka Zakrisson <daniel@hozac.com>
# (c) 2013, Javie Candeira <javier@candeira.com>
# (c) 2013, Maykel Moya <mmoya@speedyrails.com>
#
# This file is part of Ansible
#
@ -20,16 +21,23 @@ from ansible import utils, errors
import os
import errno
import random
from string import ascii_uppercase, ascii_lowercase, digits
from string import ascii_letters, digits
class LookupModule(object):
LENGTH = 20
def __init__(self, length=None, basedir=None, **kwargs):
def __init__(self, length=None, encrypt=None, basedir=None, **kwargs):
self.basedir = basedir
def random_salt(self):
salt_chars = ascii_letters + digits + './'
salt = []
for _ in range(8):
salt.append(random.choice(salt_chars))
return ''.join(salt)
def run(self, terms, inject=None, **kwargs):
terms = utils.listify_lookup_plugin_terms(terms, self.basedir, inject)
@ -40,28 +48,68 @@ class LookupModule(object):
# you can't have escaped spaces in yor pathname
params = term.split()
relpath = params[0]
length = LookupModule.LENGTH
# get non-default length parameter if specified
if len(params) > 1:
paramvals = {
'length': LookupModule.LENGTH,
'encrypt': None,
}
# get non-default parameters if specified
try:
name, length = params[1].split('=')
assert(name.startswith("length"))
length = int(length)
for param in params[1:]:
name, value = param.split('=')
assert(name in paramvals)
if name == 'length':
paramvals[name] = int(value)
else:
paramvals[name] = value
except (ValueError, AssertionError) as e:
raise errors.AnsibleError(e)
length = paramvals['length']
encrypt = paramvals['encrypt']
# get password or create it if file doesn't exist
path = utils.path_dwim(self.basedir, relpath)
if not os.path.exists(path):
pathdir = os.path.dirname(path)
if not os.path.isdir(pathdir):
os.makedirs(pathdir)
chars = ascii_uppercase + ascii_lowercase + digits + ".,:-_"
chars = ascii_letters + digits + ".,:-_"
password = ''.join(random.choice(chars) for _ in range(length))
if encrypt is not None:
salt = self.random_salt()
content = '%s salt=%s' % (password, salt)
else:
content = password
with open(path, 'w') as f:
f.write(password)
ret.append(open(path).read().rstrip())
f.write(content + '\n')
else:
content = open(path).read().rstrip()
sep = content.find(' ')
if sep >= 0:
password = content[:sep]
salt = content[sep+1:].split('=')[1]
else:
password = content
salt = None
# crypt requested, add salt if missing
if (encrypt is not None and not salt):
salt = self.random_salt()
content = '%s salt=%s' % (password, salt)
with open(path, 'w') as f:
f.write(content + '\n')
# crypt not requested, remove salt if present
elif (encrypt is None and salt):
with open(path, 'w') as f:
f.write(password + '\n')
if encrypt:
password = utils.do_encrypt(password, encrypt, salt=salt)
ret.append(password)
return ret