mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
06d92f1103
Add a new module for managing entries in an htpasswd file, used for basic authentication with web servers such as Apache and Nginx
162 lines
4.7 KiB
Python
162 lines
4.7 KiB
Python
#!/usr/bin/env python
|
|
DOCUMENTATION = """
|
|
module: htpasswd
|
|
short_description: manage user files for basic authentication
|
|
description:
|
|
- Add and remove username/password entries in a password file using htpasswd.
|
|
- This is used by web servers such as Apache and Nginx for basic authentication.
|
|
options:
|
|
path:
|
|
required: true
|
|
aliases: [ dest, destfile ]
|
|
description:
|
|
- Path to the file that contains the usernames and passwords
|
|
name:
|
|
required: true
|
|
aliases: [ username ]
|
|
description:
|
|
- User name to add or remove
|
|
password:
|
|
required: false
|
|
description:
|
|
- Password associated with user.
|
|
- Must be specified if user does not exist yet
|
|
state:
|
|
required: false
|
|
choices: [ present, absent ]
|
|
default: "present"
|
|
description:
|
|
- Whether the user entry should be present or not
|
|
create:
|
|
required: false
|
|
choices: [ "yes", "no" ]
|
|
default: "yes"
|
|
description:
|
|
- Used with C(state=present). If specified, the file will be created
|
|
if it does not already exist. If set to "no", will fail if the
|
|
file does not exist
|
|
requires: [ passlib>=1.6 ]
|
|
author: Lorin Hochstein
|
|
"""
|
|
|
|
EXAMPLES = """
|
|
# Add a user to a password file and ensure permissions are set
|
|
- htpasswd: path=/etc/nginx/passwdfile name=janedoe password=9s36?;fyNp owner=root group=www-data mode=0640
|
|
# Remove a user from a password file
|
|
- htpasswd: path=/etc/apache2/passwdfile name=foobar state=absent
|
|
"""
|
|
|
|
|
|
import os
|
|
|
|
try:
|
|
from passlib.apache import HtpasswdFile
|
|
except ImportError:
|
|
passlib_installed = False
|
|
else:
|
|
passlib_installed = True
|
|
|
|
|
|
def create_missing_directories(dest):
|
|
destpath = os.path.dirname(dest)
|
|
if not os.path.exists(destpath):
|
|
os.makedirs(destpath)
|
|
|
|
|
|
def present(dest, username, password, create, check_mode):
|
|
""" Ensures user is present
|
|
|
|
Returns (msg, changed) """
|
|
if not os.path.exists(dest):
|
|
if not create:
|
|
raise ValueError('Destination %s does not exist' % dest)
|
|
if check_mode:
|
|
return ("Create %s" % dest, True)
|
|
create_missing_directories(dest)
|
|
ht = HtpasswdFile(dest, new=True)
|
|
ht.set_password(username, password)
|
|
ht.save()
|
|
return ("Created %s and added %s" % (dest, username), True)
|
|
else:
|
|
ht = HtpasswdFile(dest, new=False)
|
|
if ht.check_password(username, password):
|
|
return ("%s already present" % username, False)
|
|
else:
|
|
if not check_mode:
|
|
ht.set_password(username, password)
|
|
ht.save()
|
|
return ("Add/update %s" % username, True)
|
|
|
|
|
|
def absent(dest, username, check_mode):
|
|
""" Ensures user is absent
|
|
|
|
Returns (msg, changed) """
|
|
if not os.path.exists(dest):
|
|
raise ValueError("%s does not exists" % dest)
|
|
|
|
ht = HtpasswdFile(dest, new=False)
|
|
if username not in ht.users():
|
|
return ("%s not present" % username, False)
|
|
else:
|
|
if not check_mode:
|
|
ht.delete(username)
|
|
ht.save()
|
|
return ("Remove %s" % username, True)
|
|
|
|
|
|
def check_file_attrs(module, changed, message):
|
|
|
|
file_args = module.load_file_common_arguments(module.params)
|
|
if module.set_file_attributes_if_different(file_args, False):
|
|
|
|
if changed:
|
|
message += " and "
|
|
changed = True
|
|
message += "ownership, perms or SE linux context changed"
|
|
|
|
return message, changed
|
|
|
|
|
|
def main():
|
|
arg_spec = dict(
|
|
path=dict(required=True, aliases=["dest", "destfile"]),
|
|
name=dict(required=True, aliases=["username"]),
|
|
password=dict(required=False, default=None),
|
|
state=dict(required=False, default="present"),
|
|
create=dict(type='bool', choices=BOOLEANS, default='yes'),
|
|
|
|
)
|
|
module = AnsibleModule(argument_spec=arg_spec,
|
|
add_file_common_args=True,
|
|
supports_check_mode=True)
|
|
|
|
path = module.params['path']
|
|
username = module.params['name']
|
|
password = module.params['password']
|
|
state = module.params['state']
|
|
create = module.params['create']
|
|
check_mode = module.check_mode
|
|
|
|
if not passlib_installed:
|
|
module.fail_json(msg="This module requires the passlib Python library")
|
|
|
|
try:
|
|
if state == 'present':
|
|
(msg, changed) = present(path, username, password, create, check_mode)
|
|
elif state == 'absent':
|
|
(msg, changed) = absent(path, username, check_mode)
|
|
else:
|
|
module.fail_json(msg="Invalid state: %s" % state)
|
|
|
|
check_file_attrs(module, changed, msg)
|
|
module.exit_json(msg=msg, changed=changed)
|
|
except Exception, e:
|
|
module.fail_json(msg=str(e))
|
|
|
|
|
|
# this is magic, see lib/ansible/module_common.py
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
|
|
if __name__ == '__main__':
|
|
main()
|