Commit b4838a33 authored by Julien Muchembled's avatar Julien Muchembled

Review generate.password recipe, dropping pwgen.*

parent 3d810d17
......@@ -165,8 +165,6 @@ setup(name=name,
'publish.serialised = slapos.recipe.publish:Serialised',
'publishsection = slapos.recipe.publish:PublishSection',
'publishurl = slapos.recipe.publishurl:Recipe',
'pwgen = slapos.recipe.pwgen:Recipe',
'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe',
'redis.server = slapos.recipe.redis:Recipe',
'request = slapos.recipe.request:Recipe',
'request.serialised = slapos.recipe.request:Serialised',
......
......@@ -26,27 +26,69 @@
#
##############################################################################
import binascii
import errno
import os
import random
import string
from slapos.recipe.librecipe import GenericBaseRecipe
def generatePassword(length):
return ''.join(random.SystemRandom().sample(string.ascii_lowercase, length))
class Recipe(GenericBaseRecipe):
class Recipe(object):
"""Generate a password that is only composed of lowercase letters
This recipe only makes sure that ${:passwd} does not end up in `.installed`
file, which is world-readable by default. So be careful not to spread it
throughout the buildout configuration by referencing it directly: see
recipes like slapos.recipe.template:jinja2 to safely process the password.
Options:
- bytes: password length (default: 8 characters)
- storage-path: plain-text persistent storage for password,
that can only be accessed by the user
(default: ${buildout:parts-directory}/${:_buildout_section_name_})
"""
def __init__(self, buildout, name, options):
if os.path.exists(options['storage-path']):
open_file = open(options['storage-path'], 'r')
options['passwd'] = open_file.read()
open_file.close()
options_get = options.get
try:
self.storage_path = options['storage-path']
except KeyError:
self.storage_path = options['storage-path'] = os.path.join(
buildout['buildout']['parts-directory'], name)
try:
with open(self.storage_path) as f:
passwd = f.read()
except IOError, e:
if e.errno != errno.ENOENT:
raise
passwd = None
if not passwd:
passwd = self.generatePassword(int(options_get('bytes', '8')))
self.update = self.install
self.passwd = passwd
# Password must not go into .installed file, for 2 reasons:
# security of course but also to prevent buildout to always reinstall.
options.get = lambda option, *args, **kw: passwd \
if option == 'passwd' else options_get(option, *args, **kw)
if options.get('passwd', '') == '':
options['passwd'] = binascii.hexlify(os.urandom(
int(options.get('bytes', '24'))))
return GenericBaseRecipe.__init__(self, buildout, name, options)
generatePassword = staticmethod(generatePassword)
def install(self):
with open(self.options['storage-path'], 'w') as fout:
fout.write(self.options['passwd'])
return [self.options['storage-path']]
if self.storage_path:
try:
os.unlink(self.storage_path)
except OSError, e:
if e.errno != errno.ENOENT:
raise
fd = os.open(self.storage_path,
os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0600)
try:
os.write(fd, self.passwd)
finally:
os.close(fd)
return self.storage_path
def update(self):
return ()
......@@ -183,17 +183,13 @@ class GenericBaseRecipe(object):
'template/%s' % template_name)
def generatePassword(self, len_=32):
"""
The purpose of this method is to generate a password which doesn't change
from one execution to the next, so the generated password doesn't change
on each slapgrid-cp execution.
Currently, it returns a hardcoded password because no decision has been
taken on where a generated password should be kept (so it is generated
once only).
"""
# TODO: implement a real password generator which remember the last
# call.
# TODO: Consider having generate.password recipe inherit this class,
# so that it can be easily inheritable.
# In the long-term, it's probably better that passwords are provided
# by software requesters, to avoid keeping unhashed secrets in
# partitions when possible.
log.warning("GenericBaseRecipe.generatePassword is deprecated."
" Use generate.password recipe instead.")
return "insecure"
def isTrueValue(self, value):
......
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import subprocess
import os
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def _options(self, options):
if not os.path.exists(self.options['file']):
password = subprocess.check_output([self.options['pwgen-binary'], '-1']).strip()
with open(self.options['file'], 'w') as password_file:
password_file.write(password)
else:
with open(self.options['file'], 'r') as password_file:
password = password_file.read()
options['password'] = password
def install(self):
os.chmod(self.options['file'], 0600)
return []
class StablePasswordGeneratorRecipe(GenericBaseRecipe):
"""
The purpose of this class is to generate a password which doesn't change
from one execution to the next (hence "stable"), so the generated password
doesn't change on each slapgrid-cp execution.
See GenericBaseRecipe.generatePassword .
"""
def _options(self, options):
options['password'] = self.generatePassword()
update = install = lambda self: []
......@@ -7,7 +7,6 @@ offline = true
parts =
connection-dict
testnode
pwgen
shell
shellinabox
certificate-authority
......@@ -16,12 +15,11 @@ parts =
[connection-dict]
recipe = slapos.cookbook:publish
url = http://[$${shellinabox:ipv6}]:$${shellinabox:port}/
password = $${pwgen:password}
password = $${pwgen:passwd}
[pwgen]
recipe = slapos.cookbook:pwgen
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
recipe = slapos.cookbook:generate.password
storage-path = $${buildout:directory}/.password
[testnode]
recipe = slapos.cookbook:erp5testnode
......@@ -82,7 +80,7 @@ port = 8080
shell = $${shell:wrapper}
wrapper = $${rootdirectory:bin}/shellinaboxd
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${pwgen:password}
password = $${pwgen:passwd}
directory = $${buildout:directory}/
login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox}
......
......@@ -20,7 +20,6 @@ extends =
../../component/zip/buildout.cfg
../../component/busybox/buildout.cfg
../../component/shellinabox/buildout.cfg
../../component/pwgen/buildout.cfg
# Local development
develop =
......
......@@ -13,14 +13,13 @@ parts =
gitdaemon
git-http-backend-cgi
htpasswd
pwgen
git-repos
[publish]
recipe = slapos.cookbook:publish
url = http://[$${slap-network-information:global-ipv6}]:$${httpd-conf:port}/
user = $${pwgen:user}
password = $${pwgen:password}
password = $${pwgen:passwd}
[httpd]
recipe = slapos.cookbook:wrapper
......@@ -79,14 +78,12 @@ output = $${basedirectory:services}/git-daemon
recipe = collective.recipe.cmd
output = $${rootdirectory:etc}/httpd.htpasswd
on_install = true
on_udptae = true
on_update = true
cmds =
${apache:location}/bin/htpasswd -cb $${:output} $${pwgen:user} $${pwgen:password}
${apache:location}/bin/htpasswd -cb $${:output} $${pwgen:user} $${pwgen:passwd}
[pwgen]
recipe = slapos.cookbook:pwgen
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
recipe = slapos.cookbook:generate.password
user = slapos
[rootdirectory]
......
......@@ -4,7 +4,6 @@ extends =
../../component/apache/buildout.cfg
../../component/perl/buildout.cfg
../../component/git/buildout.cfg
../../component/pwgen/buildout.cfg
../../stack/slapos.cfg
parts =
......
......@@ -68,9 +68,8 @@ bridge = !!BRIDGE_NAME!!
interface = lxc$${slap-network-information:network-interface}
[passwd]
recipe = slapos.cookbook:pwgen
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
recipe = slapos.cookbook:generate.password
storage-path = $${buildout:directory}/.password
[shellinabox]
recipe = slapos.cookbook:shellinabox
......@@ -79,7 +78,7 @@ port = 8080
shell = ${lxc:location}/bin/lxc-console -n $${uuid:uuid}
wrapper = $${rootdirectory:bin}/shellinaboxd_raw
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${passwd:password}
password = $${passwd:passwd}
directory = $${buildout:directory}/
login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox}
......
......@@ -10,7 +10,6 @@ extends =
../../component/xz-utils/buildout.cfg
../../component/tar/buildout.cfg
../../component/shellinabox/buildout.cfg
../../component/pwgen/buildout.cfg
../../component/bash/buildout.cfg
../../component/coreutils/buildout.cfg
......@@ -23,7 +22,6 @@ parts =
slapos-toolbox
lxc
shellinabox
pwgen
[template]
recipe = slapos.recipe.template
......
......@@ -308,9 +308,8 @@ githttpbackend = ${git:location}/libexec/git-core/git-http-backend
base-directory = $${trac-config:project_dir}/git
[trac-admin]
recipe = slapos.cookbook:pwgen
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
recipe = slapos.cookbook:generate.password
storage-path = $${buildout:directory}/.password
user = TracAdmin
#---------------------
......@@ -330,7 +329,7 @@ eggs-dirs =
python-lib = ${python2.7:location}/lib
trac-admin = ${buildout:bin-directory}/trac-admin
admin-user = $${trac-admin:user}
admin-password = $${trac-admin:password}
admin-password = $${trac-admin:passwd}
#MySQL informations
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
......@@ -401,7 +400,7 @@ port = 9000
shell = $${shell:wrapper}
wrapper = $${rootdirectory:bin}/shellinaboxd_raw
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${trac-admin:password}
password = $${trac-admin:passwd}
directory = $${inittrac:site-dir}
login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox}
......@@ -454,7 +453,7 @@ frontend_url = $${request-frontend:connection-site_url}
git = $${request-frontend:connection-site_url}git/
svn = $${request-frontend:connection-site_url}svn/
admin_user = $${trac-admin:user}
admin_password = $${trac-admin:password}
admin_password = $${trac-admin:passwd}
admin_shell = https://[$${shellinabox:ipv6}]:$${shellinabox:port}/
#----------------
......
......@@ -41,7 +41,6 @@ extends =
../../component/lxml-python/buildout.cfg
../../component/mysql-python/buildout.cfg
../../component/git/buildout.cfg
../../component/pwgen/buildout.cfg
../../component/shellinabox/buildout.cfg
../../component/perl/buildout.cfg
......
......@@ -331,7 +331,7 @@ runzope-binary = {{ bin_directory }}/runzope
bt5-repository-list =
[deadlock-debugger-password]
recipe = slapos.cookbook:pwgen.stable
recipe = slapos.cookbook:generate.password
[zope-conf-parameter-base]
ip = {{ ipv4 }}
......@@ -346,7 +346,7 @@ context =
key instance directory:instance
key instance_products directory:instance-products
raw deadlock_path /manage_debug_threads
key deadlock_debugger_password deadlock-debugger-password:password
key deadlock_debugger_password deadlock-debugger-password:passwd
key tidstorage_ip tidstorage:ip
key tidstorage_port tidstorage:port
key promise_path erp5-promise:promise-path
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment