Philipp Hörist pushed to branch master at gajim / python-nbxmpp
Commits: 62741002 by Jelmer Vernooij at 2020-10-19T14:28:41+02:00 Fix GSSAPI support and switch to GSSAPI Python module
- - - - -
5 changed files:
- README.md - nbxmpp/auth.py - nbxmpp/client.py - nbxmpp/const.py - nbxmpp/protocol.py
Changes:
===================================== README.md ===================================== @@ -11,6 +11,10 @@ - precis-i18n - idna
+## Optional Runtime Requirements + +- python-gssapi (for GSSAPI authentication) + ## Features
* List of [supported XEPs](https://dev.gajim.org/gajim/python-nbxmpp/-/wikis/Supported-XEPs-in-python-n...)
===================================== nbxmpp/auth.py ===================================== @@ -29,17 +29,16 @@ from nbxmpp.protocol import SASL_AUTH_MECHS from nbxmpp.util import b64decode from nbxmpp.util import b64encode from nbxmpp.util import LogAdapter -from nbxmpp.const import GSSAPIState from nbxmpp.const import StreamState
log = logging.getLogger('nbxmpp.auth')
try: - kerberos = __import__('kerberos') - KERBEROS_AVAILABLE = True + gssapi = __import__('gssapi') + GSSAPI_AVAILABLE = True except ImportError: - KERBEROS_AVAILABLE = False + GSSAPI_AVAILABLE = False
class SASL: @@ -91,7 +90,7 @@ class SASL: self._enabled_mechs.discard('SCRAM-SHA-256-PLUS') # channel_binding_data = None
- if not KERBEROS_AVAILABLE: + if not GSSAPI_AVAILABLE: self._enabled_mechs.discard('GSSAPI')
available_mechs = features.get_mechs() & self._enabled_mechs @@ -156,9 +155,16 @@ class SASL:
elif chosen_mechanism == 'GSSAPI': self._method = GSSAPI(self._client) - self._method.initiate(domain_based_name or - self._client.domain) - + if domain_based_name: + hostname = domain_based_name + else: + hostname = self._client.domain + try: + self._method.initiate(hostname) + except AuthFail as error: + self._log.error(error) + self._abort_auth() + return else: self._log.error('Unknown auth mech')
@@ -258,39 +264,41 @@ class ANONYMOUS:
class GSSAPI:
+ # See https://tools.ietf.org/html/rfc4752#section-3.1 + _mechanism = 'GSSAPI'
def __init__(self, client): self._client = client - self._gss_vc = None - self._state = GSSAPIState.STEP
def initiate(self, hostname): - self._gss_vc = kerberos.authGSSClientInit('xmpp@%s' % hostname)[1] - kerberos.authGSSClientStep(self._gss_vc, '') - response = kerberos.authGSSClientResponse(self._gss_vc) + service = gssapi.Name( + 'xmpp@%s' % hostname, name_type=gssapi.NameType.hostbased_service) + try: + self.ctx = gssapi.SecurityContext( + name=service, usage="initiate", + flags=gssapi.RequirementFlag.integrity) + token = self.ctx.step() + except (gssapi.exceptions.GeneralError, gssapi.raw.misc.GSSError) as e: + raise AuthFail(e) node = Node('auth', attrs={'xmlns': Namespace.SASL, 'mechanism': 'GSSAPI'}, - payload=(response or '')) + payload=b64encode(token)) self._client.send_nonza(node)
def response(self, server_message, *args, **kwargs): server_message = b64decode(server_message, bytes) - if self._state == GSSAPIState.STEP: - rc = kerberos.authGSSClientStep(self._gss_vc, server_message) - if rc != kerberos.AUTH_GSS_CONTINUE: - self._state = GSSAPIState.WRAP - elif self._state == GSSAPIState.WRAP: - rc = kerberos.authGSSClientUnwrap(self._gss_vc, server_message) - response = kerberos.authGSSClientResponse(self._gss_vc) - rc = kerberos.authGSSClientWrap( - self._gss_vc, - response, - kerberos.authGSSClientUserName(self._gss_vc)) - response = kerberos.authGSSClientResponse(self._gss_vc) - if not response: - response = '' - + try: + if not self.ctx.complete: + output_token = self.ctx.step(server_message) + else: + result = self.ctx.unwrap(server_message) + # TODO(jelmer): Log result.message + data = b'\x00\x00\x00\x00' + bytes(self.ctx.initiator_name) + output_token = self.ctx.wrap(data, False).message + except (gssapi.exceptions.GeneralError, gssapi.raw.misc.GSSError) as e: + raise AuthFail(e) + response = b64encode(output_token) node = Node('response', attrs={'xmlns': Namespace.SASL}, payload=response)
===================================== nbxmpp/client.py ===================================== @@ -279,6 +279,7 @@ class Client(Observable): def mechs(self): return set(self._allowed_mechs or set(['SCRAM-SHA-256', 'SCRAM-SHA-1', + 'GSSAPI', # 'SCRAM-SHA-256-PLUS', # 'SCRAM-SHA-1-PLUS', 'PLAIN']))
===================================== nbxmpp/const.py ===================================== @@ -21,10 +21,6 @@ from functools import total_ordering
from gi.repository import Gio
-class GSSAPIState(IntEnum): - STEP = 0 - WRAP = 1 -
class IqType(Enum): GET = 'get'
===================================== nbxmpp/protocol.py ===================================== @@ -40,8 +40,8 @@ SASL_AUTH_MECHS = [ 'SCRAM-SHA-256', 'SCRAM-SHA-1-PLUS', 'SCRAM-SHA-1', - 'PLAIN', 'GSSAPI', + 'PLAIN', 'EXTERNAL', 'ANONYMOUS', ]
View it on GitLab: https://dev.gajim.org/gajim/python-nbxmpp/-/commit/627410029884fc85bd1b5d824...