Commit 0fcf4f14 authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

htpasswd : Add htpasswd script

This script is meant to produce htpasswd file without installing apache
parent d95838e2
...@@ -61,6 +61,7 @@ setup(name=name, ...@@ -61,6 +61,7 @@ setup(name=name,
'cloudstart = slapos.cloudmgr.start:main', 'cloudstart = slapos.cloudmgr.start:main',
'cloudstop = slapos.cloudmgr.stop:main', 'cloudstop = slapos.cloudmgr.stop:main',
'equeue = slapos.equeue:main', 'equeue = slapos.equeue:main',
'htpasswd = slapos.htpasswd:main',
'killpidfromfile = slapos.systool:killpidfromfile', 'killpidfromfile = slapos.systool:killpidfromfile',
'lampconfigure = slapos.lamp:run [lampconfigure]', 'lampconfigure = slapos.lamp:run [lampconfigure]',
'onetimedownload = slapos.onetimedownload:main', 'onetimedownload = slapos.onetimedownload:main',
......
"""Replacement for htpasswd"""
# Original author: Eli Carter
# Taken from http://trac.edgewall.org/browser/trunk/contrib/htpasswd.py
import os
import sys
import random
from optparse import OptionParser
# We need a crypt module, but Windows doesn't have one by default. Try to find
# one, and tell the user if we can't.
try:
import crypt
except ImportError:
try:
import fcrypt as crypt
except ImportError:
sys.stderr.write("Cannot find a crypt module. "
"Possibly http://carey.geek.nz/code/python-fcrypt/\n")
sys.exit(1)
def salt():
"""Returns a string of 2 randome letters"""
letters = 'abcdefghijklmnopqrstuvwxyz' \
'ABCDEFGHIJKLMNOPQRSTUVWXYZ' \
'0123456789/.'
return random.choice(letters) + random.choice(letters)
class HtpasswdFile:
"""A class for manipulating htpasswd files."""
def __init__(self, filename, create=False):
self.entries = []
self.filename = filename
if not create:
if os.path.exists(self.filename):
self.load()
else:
raise Exception("%s does not exist" % self.filename)
def load(self):
"""Read the htpasswd file into memory."""
lines = open(self.filename, 'r').readlines()
self.entries = []
for line in lines:
username, pwhash = line.split(':')
entry = [username, pwhash.rstrip()]
self.entries.append(entry)
def save(self):
"""Write the htpasswd file to disk"""
open(self.filename, 'w').writelines(["%s:%s\n" % (entry[0], entry[1])
for entry in self.entries])
def update(self, username, password):
"""Replace the entry for the given user, or add it if new."""
pwhash = crypt.crypt(password, salt())
matching_entries = [entry for entry in self.entries
if entry[0] == username]
if matching_entries:
matching_entries[0][1] = pwhash
else:
self.entries.append([username, pwhash])
def delete(self, username):
"""Remove the entry for the given user."""
self.entries = [entry for entry in self.entries
if entry[0] != username]
def main():
"""%prog [-c] -b filename username password
Create or update an htpasswd file"""
# For now, we only care about the use cases that affect tests/functional.py
parser = OptionParser(usage=main.__doc__)
parser.add_option('-b', action='store_true', dest='batch', default=False,
help='Batch mode; password is passed on the command line IN THE CLEAR.'
)
parser.add_option('-c', action='store_true', dest='create', default=False,
help='Create a new htpasswd file, overwriting any existing file.')
parser.add_option('-D', action='store_true', dest='delete_user',
default=False, help='Remove the given user from the password file.')
options, args = parser.parse_args()
def syntax_error(msg):
"""Utility function for displaying fatal error messages with usage
help.
"""
sys.stderr.write("Syntax error: " + msg)
sys.stderr.write(parser.get_usage())
sys.exit(1)
if not options.batch:
syntax_error("Only batch mode is supported\n")
# Non-option arguments
if len(args) < 2:
syntax_error("Insufficient number of arguments.\n")
filename, username = args[:2]
if options.delete_user:
if len(args) != 2:
syntax_error("Incorrect number of arguments.\n")
password = None
else:
if len(args) != 3:
syntax_error("Incorrect number of arguments.\n")
password = args[2]
passwdfile = HtpasswdFile(filename, create=options.create)
if options.delete_user:
passwdfile.delete(username)
else:
passwdfile.update(username, password)
passwdfile.save()
if __name__ == '__main__':
main()
...@@ -8,6 +8,7 @@ import logging ...@@ -8,6 +8,7 @@ import logging
import multiprocessing import multiprocessing
import re import re
from slapos.runner.process import Popen, isRunning, killRunningProcess from slapos.runner.process import Popen, isRunning, killRunningProcess
from slapos.htpasswd import HtpasswdFile
import shutil import shutil
import os import os
import time import time
...@@ -64,7 +65,9 @@ def saveSession(config, account): ...@@ -64,7 +65,9 @@ def saveSession(config, account):
Returns: Returns:
True if all goes well or str (error message) if fail True if all goes well or str (error message) if fail
""" """
# XXX Cedric LN hardcoded path for files
user = os.path.join(config['etc_dir'], '.users') user = os.path.join(config['etc_dir'], '.users')
htpasswdfile = os.path.join(config['etc_dir'], '.htpasswd')
backup = False backup = False
try: try:
if os.path.exists(user): if os.path.exists(user):
...@@ -78,6 +81,13 @@ def saveSession(config, account): ...@@ -78,6 +81,13 @@ def saveSession(config, account):
account[1] = data.split(';')[1] account[1] = data.split(';')[1]
#save new account data #save new account data
open(user, 'w').write((';'.join(account)).encode("utf-8")) open(user, 'w').write((';'.join(account)).encode("utf-8"))
# Htpasswd file for cloud9
# XXX Cedric Le N order of account list values suppose to be fixed
# Remove former file to avoid aoutdated accounts
os.remove(htpasswdfile)
passwd = HtpasswdFile(htpasswdfile, create=options.create)
passwd.update(account[0], account[1])
passwd.save()
return True return True
except Exception as e: except Exception as e:
try: try:
......
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