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, ...@@ -165,8 +165,6 @@ setup(name=name,
'publish.serialised = slapos.recipe.publish:Serialised', 'publish.serialised = slapos.recipe.publish:Serialised',
'publishsection = slapos.recipe.publish:PublishSection', 'publishsection = slapos.recipe.publish:PublishSection',
'publishurl = slapos.recipe.publishurl:Recipe', 'publishurl = slapos.recipe.publishurl:Recipe',
'pwgen = slapos.recipe.pwgen:Recipe',
'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe',
'redis.server = slapos.recipe.redis:Recipe', 'redis.server = slapos.recipe.redis:Recipe',
'request = slapos.recipe.request:Recipe', 'request = slapos.recipe.request:Recipe',
'request.serialised = slapos.recipe.request:Serialised', 'request.serialised = slapos.recipe.request:Serialised',
......
...@@ -26,27 +26,69 @@ ...@@ -26,27 +26,69 @@
# #
############################################################################## ##############################################################################
import binascii import errno
import os 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): def __init__(self, buildout, name, options):
if os.path.exists(options['storage-path']): options_get = options.get
open_file = open(options['storage-path'], 'r') try:
options['passwd'] = open_file.read() self.storage_path = options['storage-path']
open_file.close() 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', '') == '': generatePassword = staticmethod(generatePassword)
options['passwd'] = binascii.hexlify(os.urandom(
int(options.get('bytes', '24'))))
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self): def install(self):
with open(self.options['storage-path'], 'w') as fout: if self.storage_path:
fout.write(self.options['passwd']) try:
return [self.options['storage-path']] 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): ...@@ -183,17 +183,13 @@ class GenericBaseRecipe(object):
'template/%s' % template_name) 'template/%s' % template_name)
def generatePassword(self, len_=32): def generatePassword(self, len_=32):
""" # TODO: Consider having generate.password recipe inherit this class,
The purpose of this method is to generate a password which doesn't change # so that it can be easily inheritable.
from one execution to the next, so the generated password doesn't change # In the long-term, it's probably better that passwords are provided
on each slapgrid-cp execution. # by software requesters, to avoid keeping unhashed secrets in
# partitions when possible.
Currently, it returns a hardcoded password because no decision has been log.warning("GenericBaseRecipe.generatePassword is deprecated."
taken on where a generated password should be kept (so it is generated " Use generate.password recipe instead.")
once only).
"""
# TODO: implement a real password generator which remember the last
# call.
return "insecure" return "insecure"
def isTrueValue(self, value): 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 ...@@ -7,7 +7,6 @@ offline = true
parts = parts =
connection-dict connection-dict
testnode testnode
pwgen
shell shell
shellinabox shellinabox
certificate-authority certificate-authority
...@@ -16,12 +15,11 @@ parts = ...@@ -16,12 +15,11 @@ parts =
[connection-dict] [connection-dict]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
url = http://[$${shellinabox:ipv6}]:$${shellinabox:port}/ url = http://[$${shellinabox:ipv6}]:$${shellinabox:port}/
password = $${pwgen:password} password = $${pwgen:passwd}
[pwgen] [pwgen]
recipe = slapos.cookbook:pwgen recipe = slapos.cookbook:generate.password
file = $${buildout:directory}/.password storage-path = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
[testnode] [testnode]
recipe = slapos.cookbook:erp5testnode recipe = slapos.cookbook:erp5testnode
...@@ -82,7 +80,7 @@ port = 8080 ...@@ -82,7 +80,7 @@ port = 8080
shell = $${shell:wrapper} shell = $${shell:wrapper}
wrapper = $${rootdirectory:bin}/shellinaboxd wrapper = $${rootdirectory:bin}/shellinaboxd
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${pwgen:password} password = $${pwgen:passwd}
directory = $${buildout:directory}/ directory = $${buildout:directory}/
login-shell = $${rootdirectory:bin}/login login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox} certificate-directory = $${directory:shellinabox}
......
...@@ -20,7 +20,6 @@ extends = ...@@ -20,7 +20,6 @@ extends =
../../component/zip/buildout.cfg ../../component/zip/buildout.cfg
../../component/busybox/buildout.cfg ../../component/busybox/buildout.cfg
../../component/shellinabox/buildout.cfg ../../component/shellinabox/buildout.cfg
../../component/pwgen/buildout.cfg
# Local development # Local development
develop = develop =
......
...@@ -13,14 +13,13 @@ parts = ...@@ -13,14 +13,13 @@ parts =
gitdaemon gitdaemon
git-http-backend-cgi git-http-backend-cgi
htpasswd htpasswd
pwgen
git-repos git-repos
[publish] [publish]
recipe = slapos.cookbook:publish recipe = slapos.cookbook:publish
url = http://[$${slap-network-information:global-ipv6}]:$${httpd-conf:port}/ url = http://[$${slap-network-information:global-ipv6}]:$${httpd-conf:port}/
user = $${pwgen:user} user = $${pwgen:user}
password = $${pwgen:password} password = $${pwgen:passwd}
[httpd] [httpd]
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
...@@ -79,14 +78,12 @@ output = $${basedirectory:services}/git-daemon ...@@ -79,14 +78,12 @@ output = $${basedirectory:services}/git-daemon
recipe = collective.recipe.cmd recipe = collective.recipe.cmd
output = $${rootdirectory:etc}/httpd.htpasswd output = $${rootdirectory:etc}/httpd.htpasswd
on_install = true on_install = true
on_udptae = true on_update = true
cmds = cmds =
${apache:location}/bin/htpasswd -cb $${:output} $${pwgen:user} $${pwgen:password} ${apache:location}/bin/htpasswd -cb $${:output} $${pwgen:user} $${pwgen:passwd}
[pwgen] [pwgen]
recipe = slapos.cookbook:pwgen recipe = slapos.cookbook:generate.password
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
user = slapos user = slapos
[rootdirectory] [rootdirectory]
......
...@@ -4,7 +4,6 @@ extends = ...@@ -4,7 +4,6 @@ extends =
../../component/apache/buildout.cfg ../../component/apache/buildout.cfg
../../component/perl/buildout.cfg ../../component/perl/buildout.cfg
../../component/git/buildout.cfg ../../component/git/buildout.cfg
../../component/pwgen/buildout.cfg
../../stack/slapos.cfg ../../stack/slapos.cfg
parts = parts =
......
...@@ -68,9 +68,8 @@ bridge = !!BRIDGE_NAME!! ...@@ -68,9 +68,8 @@ bridge = !!BRIDGE_NAME!!
interface = lxc$${slap-network-information:network-interface} interface = lxc$${slap-network-information:network-interface}
[passwd] [passwd]
recipe = slapos.cookbook:pwgen recipe = slapos.cookbook:generate.password
file = $${buildout:directory}/.password storage-path = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
[shellinabox] [shellinabox]
recipe = slapos.cookbook:shellinabox recipe = slapos.cookbook:shellinabox
...@@ -79,7 +78,7 @@ port = 8080 ...@@ -79,7 +78,7 @@ port = 8080
shell = ${lxc:location}/bin/lxc-console -n $${uuid:uuid} shell = ${lxc:location}/bin/lxc-console -n $${uuid:uuid}
wrapper = $${rootdirectory:bin}/shellinaboxd_raw wrapper = $${rootdirectory:bin}/shellinaboxd_raw
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${passwd:password} password = $${passwd:passwd}
directory = $${buildout:directory}/ directory = $${buildout:directory}/
login-shell = $${rootdirectory:bin}/login login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox} certificate-directory = $${directory:shellinabox}
......
...@@ -10,7 +10,6 @@ extends = ...@@ -10,7 +10,6 @@ extends =
../../component/xz-utils/buildout.cfg ../../component/xz-utils/buildout.cfg
../../component/tar/buildout.cfg ../../component/tar/buildout.cfg
../../component/shellinabox/buildout.cfg ../../component/shellinabox/buildout.cfg
../../component/pwgen/buildout.cfg
../../component/bash/buildout.cfg ../../component/bash/buildout.cfg
../../component/coreutils/buildout.cfg ../../component/coreutils/buildout.cfg
...@@ -23,7 +22,6 @@ parts = ...@@ -23,7 +22,6 @@ parts =
slapos-toolbox slapos-toolbox
lxc lxc
shellinabox shellinabox
pwgen
[template] [template]
recipe = slapos.recipe.template recipe = slapos.recipe.template
......
...@@ -308,9 +308,8 @@ githttpbackend = ${git:location}/libexec/git-core/git-http-backend ...@@ -308,9 +308,8 @@ githttpbackend = ${git:location}/libexec/git-core/git-http-backend
base-directory = $${trac-config:project_dir}/git base-directory = $${trac-config:project_dir}/git
[trac-admin] [trac-admin]
recipe = slapos.cookbook:pwgen recipe = slapos.cookbook:generate.password
file = $${buildout:directory}/.password storage-path = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
user = TracAdmin user = TracAdmin
#--------------------- #---------------------
...@@ -330,7 +329,7 @@ eggs-dirs = ...@@ -330,7 +329,7 @@ eggs-dirs =
python-lib = ${python2.7:location}/lib python-lib = ${python2.7:location}/lib
trac-admin = ${buildout:bin-directory}/trac-admin trac-admin = ${buildout:bin-directory}/trac-admin
admin-user = $${trac-admin:user} admin-user = $${trac-admin:user}
admin-password = $${trac-admin:password} admin-password = $${trac-admin:passwd}
#MySQL informations #MySQL informations
mysql-username = $${mariadb-urlparse:username} mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password} mysql-password = $${mariadb-urlparse:password}
...@@ -401,7 +400,7 @@ port = 9000 ...@@ -401,7 +400,7 @@ port = 9000
shell = $${shell:wrapper} shell = $${shell:wrapper}
wrapper = $${rootdirectory:bin}/shellinaboxd_raw wrapper = $${rootdirectory:bin}/shellinaboxd_raw
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${trac-admin:password} password = $${trac-admin:passwd}
directory = $${inittrac:site-dir} directory = $${inittrac:site-dir}
login-shell = $${rootdirectory:bin}/login login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox} certificate-directory = $${directory:shellinabox}
...@@ -454,7 +453,7 @@ frontend_url = $${request-frontend:connection-site_url} ...@@ -454,7 +453,7 @@ frontend_url = $${request-frontend:connection-site_url}
git = $${request-frontend:connection-site_url}git/ git = $${request-frontend:connection-site_url}git/
svn = $${request-frontend:connection-site_url}svn/ svn = $${request-frontend:connection-site_url}svn/
admin_user = $${trac-admin:user} admin_user = $${trac-admin:user}
admin_password = $${trac-admin:password} admin_password = $${trac-admin:passwd}
admin_shell = https://[$${shellinabox:ipv6}]:$${shellinabox:port}/ admin_shell = https://[$${shellinabox:ipv6}]:$${shellinabox:port}/
#---------------- #----------------
......
...@@ -41,7 +41,6 @@ extends = ...@@ -41,7 +41,6 @@ extends =
../../component/lxml-python/buildout.cfg ../../component/lxml-python/buildout.cfg
../../component/mysql-python/buildout.cfg ../../component/mysql-python/buildout.cfg
../../component/git/buildout.cfg ../../component/git/buildout.cfg
../../component/pwgen/buildout.cfg
../../component/shellinabox/buildout.cfg ../../component/shellinabox/buildout.cfg
../../component/perl/buildout.cfg ../../component/perl/buildout.cfg
......
...@@ -331,7 +331,7 @@ runzope-binary = {{ bin_directory }}/runzope ...@@ -331,7 +331,7 @@ runzope-binary = {{ bin_directory }}/runzope
bt5-repository-list = bt5-repository-list =
[deadlock-debugger-password] [deadlock-debugger-password]
recipe = slapos.cookbook:pwgen.stable recipe = slapos.cookbook:generate.password
[zope-conf-parameter-base] [zope-conf-parameter-base]
ip = {{ ipv4 }} ip = {{ ipv4 }}
...@@ -346,7 +346,7 @@ context = ...@@ -346,7 +346,7 @@ context =
key instance directory:instance key instance directory:instance
key instance_products directory:instance-products key instance_products directory:instance-products
raw deadlock_path /manage_debug_threads 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_ip tidstorage:ip
key tidstorage_port tidstorage:port key tidstorage_port tidstorage:port
key promise_path erp5-promise:promise-path 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