FreeIPA module polymorphic restructuring and small fixes. (#3485)

* Moved JSON-RPC client IPAClient class to ansible.module_utils.ipa, which is extended by all ipa modules
* ipa_user: incorporate displayname and userpassword attributes in module_user
* ipa_user: capitalized "I" in comment
* ipa_user: updated get_ssh_key_fingerprint to include possibility of the uploaded SSH key including user@hostname comment, which also appears in the queried fingerprint. This fixes a mismatch in the calculated and queried SSH key fingerprint in the user_diff calculation when the user already exists.
* ipa_hbacrule: ipaenabledflag must be 'TRUE' or 'FALSE', not 'NO'
* ipa_sudorule: ipaenabledflag must be 'TRUE' or 'FALSE', not 'NO'
* Add author to files missing it
This commit is contained in:
Matthew Krupcale 2016-12-04 05:44:43 -05:00 committed by Matt Clay
parent 92a53a7182
commit a6f0a279a9
9 changed files with 88 additions and 738 deletions

View file

@ -87,8 +87,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -137,83 +135,12 @@ group:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class GroupIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(GroupIPAClient, self).__init__(module, host, port, protocol)
def group_find(self, name):
return self._post_json(method='group_find', name=None, item={'all': True, 'cn': name})
@ -364,10 +291,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = GroupIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
password=module.params['ipa_pass'])
@ -380,7 +307,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -122,8 +122,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -168,83 +166,12 @@ hbacrule:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class HBACRuleIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(HBACRuleIPAClient, self).__init__(module, host, port, protocol)
def hbacrule_find(self, name):
return self._post_json(method='hbacrule_find', name=None, item={'all': True, 'cn': name})
@ -341,7 +268,7 @@ def ensure(module, client):
if state in ['present', 'enabled']:
ipaenabledflag = 'TRUE'
else:
ipaenabledflag = 'NO'
ipaenabledflag = 'FALSE'
host = module.params['host']
hostcategory = module.params['hostcategory']
@ -458,10 +385,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = HBACRuleIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
@ -475,7 +402,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -18,6 +18,7 @@
DOCUMENTATION = '''
---
module: ipa_host
author: Thomas Krahn (@Nosmoht)
short_description: Manage FreeIPA host
description:
- Add, modify and delete an IPA host using IPA API
@ -104,8 +105,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -161,83 +160,12 @@ host_diff:
type: list
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class HostIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(HostIPAClient, self).__init__(module, host, port, protocol)
def host_find(self, name):
return self._post_json(method='host_find', name=None, item={'all': True, 'fqdn': name})
@ -357,10 +285,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = HostIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
@ -374,7 +302,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -18,6 +18,7 @@
DOCUMENTATION = '''
---
module: ipa_hostgroup
author: Thomas Krahn (@Nosmoht)
short_description: Manage FreeIPA host-group
description:
- Add, modify and delete an IPA host-group using IPA API
@ -80,8 +81,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -114,83 +113,12 @@ hostgroup:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class HostGroupIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(HostGroupIPAClient, self).__init__(module, host, port, protocol)
def hostgroup_find(self, name):
return self._post_json(method='hostgroup_find', name=None, item={'all': True, 'cn': name})
@ -324,10 +252,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = HostGroupIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
@ -341,7 +269,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -18,6 +18,7 @@
DOCUMENTATION = '''
---
module: ipa_role
author: Thomas Krahn (@Nosmoht)
short_description: Manage FreeIPA role
description:
- Add, modify and delete a role within FreeIPA server using FreeIPA API
@ -98,8 +99,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -144,83 +143,12 @@ role:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class RoleIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(RoleIPAClient, self).__init__(module, host, port, protocol)
def role_find(self, name):
return self._post_json(method='role_find', name=None, item={'all': True, 'cn': name})
@ -390,10 +318,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = RoleIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
@ -407,7 +335,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -65,8 +65,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -94,83 +92,12 @@ sudocmd:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class SudoCmdIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(SudoCmdIPAClient, self).__init__(module, host, port, protocol)
def sudocmd_find(self, name):
return self._post_json(method='sudocmd_find', name=None, item={'all': True, 'sudocmd': name})
@ -255,10 +182,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = SudoCmdIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
password=module.params['ipa_pass'])
@ -271,7 +198,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -70,8 +70,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -101,83 +99,12 @@ sudocmdgroup:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class SudoCmdGroupIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(SudoCmdGroupIPAClient, self).__init__(module, host, port, protocol)
def sudocmdgroup_find(self, name):
return self._post_json(method='sudocmdgroup_find', name=None, item={'all': True, 'cn': name})
@ -297,10 +224,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = SudoCmdGroupIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
password=module.params['ipa_pass'])
@ -313,7 +240,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -111,8 +111,6 @@ options:
required: false
default: true
version_added: "2.3"
requirements:
- json
'''
EXAMPLES = '''
@ -153,83 +151,12 @@ sudorule:
type: dict
'''
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class SudoRuleIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(SudoRuleIPAClient, self).__init__(module, host, port, protocol)
def sudorule_find(self, name):
return self._post_json(method='sudorule_find', name=None, item={'all': True, 'cn': name})
@ -368,7 +295,7 @@ def ensure(module, client):
if state in ['present', 'enabled']:
ipaenabledflag = 'TRUE'
else:
ipaenabledflag = 'NO'
ipaenabledflag = 'FALSE'
sudoopt = module.params['sudoopt']
user = module.params['user']
@ -472,10 +399,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = SudoRuleIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
try:
client.login(username=module.params['ipa_user'],
password=module.params['ipa_pass'])
@ -488,7 +415,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()

View file

@ -18,6 +18,7 @@
DOCUMENTATION = '''
---
module: ipa_user
author: Thomas Krahn (@Nosmoht)
short_description: Manage FreeIPA users
description:
- Add, modify and delete user within IPA server
@ -99,7 +100,6 @@ version_added: "2.3"
requirements:
- base64
- hashlib
- json
'''
EXAMPLES = '''
@ -139,83 +139,12 @@ user:
import base64
import hashlib
try:
import json
except ImportError:
import simplejson as json
from ansible.module_utils.ipa import IPAClient
class UserIPAClient(IPAClient):
class IPAClient:
def __init__(self, module, host, port, protocol):
self.host = host
self.port = port
self.protocol = protocol
self.module = module
self.headers = None
def get_base_url(self):
return '%s://%s/ipa' % (self.protocol, self.host)
def get_json_url(self):
return '%s/session/json' % self.get_base_url()
def login(self, username, password):
url = '%s/session/login_password' % self.get_base_url()
data = 'user=%s&password=%s' % (username, password)
headers = {'referer': self.get_base_url(),
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'text/plain'}
try:
resp, info = fetch_url(module=self.module, url=url, data=data, headers=headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail('login', info['body'])
self.headers = {'referer': self.get_base_url(),
'Content-Type': 'application/json',
'Accept': 'application/json',
'Cookie': resp.info().getheader('Set-Cookie')}
except Exception:
e = get_exception()
self._fail('login', str(e))
def _fail(self, msg, e):
if 'message' in e:
err_string = e.get('message')
else:
err_string = e
self.module.fail_json(msg='%s: %s' % (msg, err_string))
def _post_json(self, method, name, item=None):
if item is None:
item = {}
url = '%s/session/json' % self.get_base_url()
data = {'method': method, 'params': [[name], item]}
try:
resp, info = fetch_url(module=self.module, url=url, data=json.dumps(data), headers=self.headers)
status_code = info['status']
if status_code not in [200, 201, 204]:
self._fail(method, info['body'])
except Exception:
e = get_exception()
self._fail('post %s' % method, str(e))
resp = json.loads(resp.read())
err = resp.get('error')
if err is not None:
self._fail('repsonse %s' % method, err)
if 'result' in resp:
result = resp.get('result')
if 'result' in result:
result = result.get('result')
if isinstance(result, list):
if len(result) > 0:
return result[0]
else:
return {}
return result
return None
super(UserIPAClient, self).__init__(module, host, port, protocol)
def user_find(self, name):
return self._post_json(method='user_find', name=None, item={'all': True, 'uid': name})
@ -236,10 +165,11 @@ class IPAClient:
return self._post_json(method='user_enable', name=name)
def get_user_dict(givenname=None, loginshell=None, mail=None, nsaccountlock=False, sn=None, sshpubkey=None,
telephonenumber=None,
title=None):
def get_user_dict(displayname=None, givenname=None, loginshell=None, mail=None, nsaccountlock=False, sn=None,
sshpubkey=None, telephonenumber=None, title=None, userpassword=None):
user = {}
if displayname is not None:
user['displayname'] = displayname
if givenname is not None:
user['givenname'] = givenname
if loginshell is not None:
@ -255,6 +185,8 @@ def get_user_dict(givenname=None, loginshell=None, mail=None, nsaccountlock=Fals
user['telephonenumber'] = telephonenumber
if title is not None:
user['title'] = title
if userpassword is not None:
user['userpassword'] = userpassword
return user
@ -265,7 +197,7 @@ def get_user_diff(ipa_user, module_user):
API returns everything as a list even if only a single value is possible.
Therefore some more complexity is needed.
The method will check if the value type of module_user.attr is not a list and
create a list with that element if the same attribute in ipa_user is list. In this way i hope that the method
create a list with that element if the same attribute in ipa_user is list. In this way I hope that the method
must not be changed if the returned API dict is changed.
:param ipa_user:
:param module_user:
@ -301,7 +233,7 @@ def get_user_diff(ipa_user, module_user):
def get_ssh_key_fingerprint(ssh_key):
"""
Return the public key fingerprint of a given public SSH key
in format "FB:0C:AC:0A:07:94:5B:CE:75:6E:63:32:13:AD:AD:D7 (ssh-rsa)"
in format "FB:0C:AC:0A:07:94:5B:CE:75:6E:63:32:13:AD:AD:D7 [user@host] (ssh-rsa)"
:param ssh_key:
:return:
"""
@ -312,7 +244,12 @@ def get_ssh_key_fingerprint(ssh_key):
key = base64.b64decode(parts[1].encode('ascii'))
fp_plain = hashlib.md5(key).hexdigest()
return ':'.join(a + b for a, b in zip(fp_plain[::2], fp_plain[1::2])).upper() + ' (%s)' % key_type
key_fp = ':'.join(a + b for a, b in zip(fp_plain[::2], fp_plain[1::2])).upper()
if len(parts) < 3:
return "%s (%s)" % (key_fp, key_type)
else:
user_host = parts[2]
return "%s %s (%s)" % (key_fp, user_host, key_type)
def ensure(module, client):
@ -320,10 +257,13 @@ def ensure(module, client):
name = module.params['name']
nsaccountlock = state == 'disabled'
module_user = get_user_dict(givenname=module.params.get('givenname'), loginshell=module.params['loginshell'],
module_user = get_user_dict(displayname=module.params.get('displayname'),
givenname=module.params.get('givenname'),
loginshell=module.params['loginshell'],
mail=module.params['mail'], sn=module.params['sn'],
sshpubkey=module.params['sshpubkey'], nsaccountlock=nsaccountlock,
telephonenumber=module.params['telephonenumber'], title=module.params['title'])
telephonenumber=module.params['telephonenumber'], title=module.params['title'],
userpassword=module.params['password'])
ipa_user = client.user_find(name=name)
@ -373,10 +313,10 @@ def main():
supports_check_mode=True,
)
client = IPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
client = UserIPAClient(module=module,
host=module.params['ipa_host'],
port=module.params['ipa_port'],
protocol=module.params['ipa_prot'])
# If sshpubkey is defined as None than module.params['sshpubkey'] is [None]. IPA itself returns None (not a list).
# Therefore a small check here to replace list(None) by None. Otherwise get_user_diff() would return sshpubkey
@ -397,7 +337,6 @@ def main():
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
if __name__ == '__main__':
main()