mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-24 19:31:26 -07:00
identity: Add GSSAPI suport for FreeIPA authentication (#52031)
* identity: Add GSSAPI suport for FreeIPA authentication This enables the usage of GSSAPI for authentication, instead of having to pass the username and password as part of the playbook run. If there is GSSAPI support, this makes the password optional, and will be able to use the KRB5_CLIENT_KTNAME or the KRB5CCNAME environment variables; which are standard when using kerberos authentication. Note that this depends on the urllib_gssapi library, and will only enable this if that library is available. * identity: Add documentation for GSSAPI authentication for FreeIPA This documentation describes how to use GSSAPI authentication with the IPA identity modules. * identity: Add changelog for GSSAPI support for IPA This adds the changelog entry for the GSSAPI authentication feature for the IPA identity module.
This commit is contained in:
parent
7d55dc1a38
commit
9f081ca04f
6 changed files with 69 additions and 29 deletions
|
@ -28,13 +28,15 @@
|
|||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import uuid
|
||||
|
||||
import re
|
||||
from ansible.module_utils._text import to_bytes, to_native, to_text
|
||||
from ansible.module_utils.six import PY3
|
||||
from ansible.module_utils.six.moves.urllib.parse import quote
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
from ansible.module_utils.urls import fetch_url, HAS_GSSAPI
|
||||
from ansible.module_utils.basic import env_fallback, AnsibleFallbackNotFound
|
||||
|
||||
|
||||
|
@ -60,6 +62,7 @@ class IPAClient(object):
|
|||
self.module = module
|
||||
self.headers = None
|
||||
self.timeout = module.params.get('ipa_timeout')
|
||||
self.use_gssapi = False
|
||||
|
||||
def get_base_url(self):
|
||||
return '%s://%s/ipa' % (self.protocol, self.host)
|
||||
|
@ -68,23 +71,38 @@ class IPAClient(object):
|
|||
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' % (quote(username, safe=''), quote(password, safe=''))
|
||||
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=to_bytes(data), headers=headers, timeout=self.timeout)
|
||||
status_code = info['status']
|
||||
if status_code not in [200, 201, 204]:
|
||||
self._fail('login', info['msg'])
|
||||
if 'KRB5CCNAME' in os.environ and HAS_GSSAPI:
|
||||
self.use_gssapi = True
|
||||
elif 'KRB5_CLIENT_KTNAME' in os.environ and HAS_GSSAPI:
|
||||
ccache = "MEMORY:" + str(uuid.uuid4())
|
||||
os.environ['KRB5CCNAME'] = ccache
|
||||
self.use_gssapi = True
|
||||
else:
|
||||
if not password:
|
||||
self._fail('login', 'Password is required if not using '
|
||||
'GSSAPI. To use GSSAPI, please set the '
|
||||
'KRB5_CLIENT_KTNAME or KRB5CCNAME (or both) '
|
||||
' environment variables.')
|
||||
url = '%s/session/login_password' % self.get_base_url()
|
||||
data = 'user=%s&password=%s' % (quote(username, safe=''), quote(password, safe=''))
|
||||
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=to_bytes(data), headers=headers, timeout=self.timeout)
|
||||
status_code = info['status']
|
||||
if status_code not in [200, 201, 204]:
|
||||
self._fail('login', info['msg'])
|
||||
|
||||
self.headers = {'referer': self.get_base_url(),
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'Cookie': resp.info().get('Set-Cookie')}
|
||||
except Exception as e:
|
||||
self._fail('login', to_native(e))
|
||||
self.headers = {'Cookie': resp.info().get('Set-Cookie')}
|
||||
except Exception as e:
|
||||
self._fail('login', to_native(e))
|
||||
if not self.headers:
|
||||
self.headers = dict()
|
||||
self.headers.update({
|
||||
'referer': self.get_base_url(),
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'})
|
||||
|
||||
def _fail(self, msg, e):
|
||||
if 'message' in e:
|
||||
|
@ -120,7 +138,8 @@ class IPAClient(object):
|
|||
data['params'] = [[name], item]
|
||||
|
||||
try:
|
||||
resp, info = fetch_url(module=self.module, url=url, data=to_bytes(json.dumps(data)), headers=self.headers, timeout=self.timeout)
|
||||
resp, info = fetch_url(module=self.module, url=url, data=to_bytes(json.dumps(data)),
|
||||
headers=self.headers, timeout=self.timeout, use_gssapi=self.use_gssapi)
|
||||
status_code = info['status']
|
||||
if status_code not in [200, 201, 204]:
|
||||
self._fail(method, info['msg'])
|
||||
|
@ -199,7 +218,7 @@ def ipa_argument_spec():
|
|||
ipa_host=dict(type='str', default='ipa.example.com', fallback=(_env_then_dns_fallback, ['IPA_HOST'])),
|
||||
ipa_port=dict(type='int', default=443, fallback=(env_fallback, ['IPA_PORT'])),
|
||||
ipa_user=dict(type='str', default='admin', fallback=(env_fallback, ['IPA_USER'])),
|
||||
ipa_pass=dict(type='str', required=True, no_log=True, fallback=(env_fallback, ['IPA_PASS'])),
|
||||
ipa_pass=dict(type='str', required=not HAS_GSSAPI, no_log=True, fallback=(env_fallback, ['IPA_PASS'])),
|
||||
ipa_timeout=dict(type='int', default=10, fallback=(env_fallback, ['IPA_TIMEOUT'])),
|
||||
validate_certs=dict(type='bool', default=True),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue