mirror of https://github.com/k3s-io/k3s
Remove the dependency on apache htpasswd.
parent
affaf173bf
commit
4eccd64e0f
|
@ -47,7 +47,7 @@ trap "rm -rf ${KUBE_TEMP}" EXIT
|
|||
|
||||
get-password
|
||||
echo "Using password: $user:$passwd"
|
||||
htpasswd -b -c ${KUBE_TEMP}/htpasswd $user $passwd
|
||||
python $(dirname $0)/../third_party/htpasswd/htpasswd.py -b -c ${KUBE_TEMP}/htpasswd $user $passwd
|
||||
HTPASSWD=$(cat ${KUBE_TEMP}/htpasswd)
|
||||
|
||||
(
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Copyright (C) 2003-2013 Edgewall Software
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
3. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,153 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2008-2013 Edgewall Software
|
||||
# Copyright (C) 2008 Eli Carter
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software is licensed as described in the file COPYING, which
|
||||
# you should have received as part of this distribution. The terms
|
||||
# are also available at http://trac.edgewall.com/license.html.
|
||||
#
|
||||
# This software consists of voluntary contributions made by many
|
||||
# individuals. For the exact contribution history, see the revision
|
||||
# history and logs, available at http://trac.edgewall.org/.
|
||||
|
||||
"""Replacement for htpasswd"""
|
||||
|
||||
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 wait_for_file_mtime_change(filename):
|
||||
"""This function is typically called before a file save operation,
|
||||
waiting if necessary for the file modification time to change. The
|
||||
purpose is to avoid successive file updates going undetected by the
|
||||
caching mechanism that depends on a change in the file modification
|
||||
time to know when the file should be reparsed."""
|
||||
try:
|
||||
mtime = os.stat(filename).st_mtime
|
||||
os.utime(filename, None)
|
||||
while mtime == os.stat(filename).st_mtime:
|
||||
time.sleep(1e-3)
|
||||
os.utime(filename, None)
|
||||
except OSError:
|
||||
pass # file doesn't exist (yet)
|
||||
|
||||
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"""
|
||||
wait_for_file_mtime_change(self.filename)
|
||||
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 -b[c] filename username password
|
||||
%prog -D filename username"""
|
||||
# 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 or options.delete_user):
|
||||
syntax_error("Only batch and delete modes are 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()
|
Loading…
Reference in New Issue