Merge pull request #4686 from bcoca/postgresql_user_pwds

postgresql_user now supports users w/o a password, encrypted passwords and expiration
This commit is contained in:
jctanner 2013-11-14 08:55:11 -08:00
commit 8041735c56

View file

@ -43,8 +43,8 @@ options:
default: null default: null
password: password:
description: description:
- set the user's password - set the user's password, before 1.4 this was requried.
required: true required: false
default: null default: null
db: db:
description: description:
@ -90,6 +90,18 @@ options:
required: false required: false
default: present default: present
choices: [ "present", "absent" ] choices: [ "present", "absent" ]
encrypted:
description:
- denotes if the password is already encrypted. boolean.
required: false
default: false
version_added: '1.4'
expires:
description:
- sets the user's password expiration.
required: false
default: null
version_added: '1.4'
notes: notes:
- The default authentication assumes that you are either logging in as or - The default authentication assumes that you are either logging in as or
sudo'ing to the postgres account on the host. sudo'ing to the postgres account on the host.
@ -121,6 +133,9 @@ EXAMPLES = '''
# Example privileges string format # Example privileges string format
INSERT,UPDATE/table:SELECT/anothertable:ALL INSERT,UPDATE/table:SELECT/anothertable:ALL
# Remove an existing user's password
- postgresql_user: db=test user=test password=NULL
''' '''
import re import re
@ -146,15 +161,18 @@ def user_exists(cursor, user):
return cursor.rowcount > 0 return cursor.rowcount > 0
def user_add(cursor, user, password, role_attr_flags): def user_add(cursor, user, password, role_attr_flags, encrypted, expires):
"""Create a new database user (role).""" """Create a new database user (role)."""
query = 'CREATE USER "%(user)s" WITH PASSWORD %%(password)s %(role_attr_flags)s' % { query = 'CREATE USER "%(user)s"' % { "user": user}
"user": user, "role_attr_flags": role_attr_flags if password is not None:
} query = query + " WITH %(crypt)s PASSWORD '%(password)s'" % { "crypt": encrypted, "password": password }
cursor.execute(query, {"password": password}) if expires is not None:
query = query + " VALID UNTIL '%(expires)s'" % { "exipres": expires }
query = query + " " + role_attr_flags
cursor.execute(query)
return True return True
def user_alter(cursor, user, password, role_attr_flags): def user_alter(cursor, user, password, role_attr_flags, encrypted, expires):
"""Change user password and/or attributes. Return True if changed, False otherwise.""" """Change user password and/or attributes. Return True if changed, False otherwise."""
changed = False changed = False
@ -174,16 +192,18 @@ def user_alter(cursor, user, password, role_attr_flags):
# Grab current role attributes. # Grab current role attributes.
current_role_attrs = cursor.fetchone() current_role_attrs = cursor.fetchone()
alter = 'ALTER USER "%(user)s"' % {"user": user}
if password is not None: if password is not None:
# Update the role attributes, including password. alter = alter + " WITH %(crypt)s PASSWORD '%(password)s' %(flags)s" % {
alter = 'ALTER USER "%(user)s" WITH PASSWORD %%(password)s %(role_attr_flags)s' % { "crypt": encrypted, "password": password, "flags": role_attr_flags
"user": user, "role_attr_flags": role_attr_flags
} }
cursor.execute(alter, {"password": password}) elif role_attr_flags:
else: alter = alter + ' WITH ' + role_attr_flags
# Update the role attributes, excluding password. if expires is not None:
alter = "ALTER USER \"%(user)s\" WITH %(role_attr_flags)s" alter = alter + " VALID UNTIL '%(expires)s'" % { "exipres": expires }
cursor.execute(alter % {"user": user, "role_attr_flags": role_attr_flags})
cursor.execute(alter)
# Grab new role attributes. # Grab new role attributes.
cursor.execute(select, {"user": user}) cursor.execute(select, {"user": user})
new_role_attrs = cursor.fetchone() new_role_attrs = cursor.fetchone()
@ -383,8 +403,10 @@ def main():
priv=dict(default=None), priv=dict(default=None),
db=dict(default=''), db=dict(default=''),
port=dict(default='5432'), port=dict(default='5432'),
fail_on_user=dict(default='yes'), fail_on_user=dict(type='bool', choices=BOOLEANS, default='yes'),
role_attr_flags=dict(default='') role_attr_flags=dict(default=''),
encrypted=dict(type='bool', choices=BOOLEANS, default='no'),
expires=dict(default=None)
), ),
supports_check_mode = True supports_check_mode = True
) )
@ -392,13 +414,18 @@ def main():
user = module.params["user"] user = module.params["user"]
password = module.params["password"] password = module.params["password"]
state = module.params["state"] state = module.params["state"]
fail_on_user = module.params["fail_on_user"] == 'yes' fail_on_user = module.params["fail_on_user"]
db = module.params["db"] db = module.params["db"]
if db == '' and module.params["priv"] is not None: if db == '' and module.params["priv"] is not None:
module.fail_json(msg="privileges require a database to be specified") module.fail_json(msg="privileges require a database to be specified")
privs = parse_privs(module.params["priv"], db) privs = parse_privs(module.params["priv"], db)
port = module.params["port"] port = module.params["port"]
role_attr_flags = parse_role_attrs(module.params["role_attr_flags"]) role_attr_flags = parse_role_attrs(module.params["role_attr_flags"])
if module.params["encrypted"]:
encrypted = "ENCRYPTED"
else:
encrypted = "UNENCRYPTED"
expires = module.params["expires"]
if not postgresqldb_found: if not postgresqldb_found:
module.fail_json(msg="the python psycopg2 module is required") module.fail_json(msg="the python psycopg2 module is required")
@ -426,32 +453,17 @@ def main():
user_removed = False user_removed = False
if state == "present": if state == "present":
if user_exists(cursor, user): if user_exists(cursor, user):
if module.check_mode: changed = user_alter(cursor, user, password, role_attr_flags, encrypted, expires)
kw['changed'] = True
module.exit_json(**kw)
changed = user_alter(cursor, user, password, role_attr_flags)
else: else:
if password is None: changed = user_add(cursor, user, password, role_attr_flags, encrypted, expires)
msg = "password parameter required when adding a user"
module.fail_json(msg=msg)
if module.check_mode:
kw['changed'] = True
module.exit_json(**kw)
changed = user_add(cursor, user, password, role_attr_flags)
changed = grant_privileges(cursor, user, privs) or changed changed = grant_privileges(cursor, user, privs) or changed
else: else:
if user_exists(cursor, user): if user_exists(cursor, user):
if module.check_mode: if module.check_mode:
kw['changed'] = True changed = True
kw['user_removed'] = True kw['user_removed'] = True
module.exit_json(**kw) else:
changed = revoke_privileges(cursor, user, privs) changed = revoke_privileges(cursor, user, privs)
user_removed = user_delete(cursor, user) user_removed = user_delete(cursor, user)
changed = changed or user_removed changed = changed or user_removed
@ -461,6 +473,9 @@ def main():
kw['user_removed'] = user_removed kw['user_removed'] = user_removed
if changed: if changed:
if module.check_mode:
db_connection.rollback()
else:
db_connection.commit() db_connection.commit()
kw['changed'] = changed kw['changed'] = changed