anvil/devstack/passwords.py
2012-03-16 15:38:38 -04:00

97 lines
3.2 KiB
Python

# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (C) 2012 Yahoo! Inc. All Rights Reserved.
# Copyright (C) 2012 New Dream Network, LLC (DreamHost) All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import binascii
import getpass
import logging
import os
import re
LOG = logging.getLogger("devstack.passwords")
PW_SECTION = 'passwords'
def generate_random(length):
"""Returns a randomly generated password of the specified length."""
LOG.debug("Generating a pseudo-random password of %d characters",
length)
return binascii.hexlify(os.urandom((length + 1) / 2))[:length]
class PasswordGenerator(object):
def __init__(self, cfg, prompt_user=True):
self.cfg = cfg
self.prompt_user = prompt_user
def _valid_password(self, pw):
# FIXME: More efficient way to look for whitespace?
if re.match(r"^(\s+)$", pw) or \
re.match(r"^(\s+)(\S+)(\s+)$", pw) or \
re.match(r"^(\S+)(\s+)$", pw) or \
re.match(r"^(\s+)(\S+)$", pw):
return False
return True
def _prompt_user(self, prompt_text):
LOG.debug('Asking the user for a %r password', prompt_text)
message = ("Enter a password to use for %s "
"[or press enter to get a generated one]: " % prompt_text
)
rc = ""
while True:
rc = getpass.getpass(message)
if len(rc) == 0 or self._valid_password(rc):
break
else:
LOG.warn("Invalid password \"%s\" (please try again)" % (rc))
return rc
def extract(self, option):
return self.cfg.get(PW_SECTION, option)
def _set_through(self, option, value):
self.cfg.set(PW_SECTION, option, value)
def get_password(self, option, prompt_text, length=8):
"""Returns a password identified by the configuration location."""
LOG.debug('Looking for password %s (%s)', option, prompt_text)
# Look in the configuration file(s)
password = None
from_config = False
if not password:
password = self.cfg.get(PW_SECTION, option)
if password:
from_config = True
# Optionally ask the user
if not password and self.prompt_user:
password = self._prompt_user(prompt_text)
# If we still don't have a value, make one up.
if not password:
LOG.debug('No configured password for %s (%s)',
option, prompt_text)
password = generate_random(length)
# Update via set through to the config
if not from_config:
self._set_through(option, password)
return password