docs: def _authenticate_gssapi(credentials, sock_info):
      """Authenticate using GSSAPI.
      """
      if not HAVE_KERBEROS:
          raise ConfigurationError('The "kerberos" module must be '
                                   'installed to use GSSAPI authentication.')
  
      try:
          username = credentials.username
          password = credentials.password
          props = credentials.mechanism_properties
          # Starting here and continuing through the while loop below - establish
          # the security context. See RFC 4752, Section 3.1, first paragraph.
          host = sock_info.address[0]
          if props.canonicalize_host_name:
              host = socket.getfqdn(host)
          service = props.service_name + '@' + host
          if props.service_realm is not None:
              service = service + '@' + props.service_realm
  
          if password is not None:
              if _USE_PRINCIPAL:
                  # Note that, though we use unquote_plus for unquoting URI
                  # options, we use quote here. Microsoft's UrlUnescape (used
                  # by WinKerberos) doesn't support +.
                  principal = ":".join((quote(username), quote(password)))
                  result, ctx = kerberos.authGSSClientInit(
                      service, principal, gssflags=kerberos.GSS_C_MUTUAL_FLAG)
              else:
                  if '@' in username:
                      user, domain = username.split('@', 1)
                  else:
                      user, domain = username, None
                  result, ctx = kerberos.authGSSClientInit(
                      service, gssflags=kerberos.GSS_C_MUTUAL_FLAG,
                      user=user, domain=domain, password=password)
          else:
              result, ctx = kerberos.authGSSClientInit(
                  service, gssflags=kerberos.GSS_C_MUTUAL_FLAG)
  
          if result != kerberos.AUTH_GSS_COMPLETE:
              raise OperationFailure('Kerberos context failed to initialize.')
  
          try:
              # pykerberos uses a weird mix of exceptions and return values
              # to indicate errors.
              # 0 == continue, 1 == complete, -1 == error
              # Only authGSSClientStep can return 0.
              if kerberos.authGSSClientStep(ctx, '') != 0:
                  raise OperationFailure('Unknown kerberos '
                                         'failure in step function.')
  
              # Start a SASL conversation with mongod/s
              # Note: pykerberos deals with base64 encoded byte strings.
              # Since mongo accepts base64 strings as the payload we don't
              # have to use bson.binary.Binary.
              payload = kerberos.authGSSClientResponse(ctx)
              cmd = SON([('saslStart', 1),
                         ('mechanism', 'GSSAPI'),
                         ('payload', payload),
                         ('autoAuthorize', 1)])
              response = sock_info.command('$external', cmd)
  
              # Limit how many times we loop to catch protocol / library issues
              for _ in range(10):
                  result = kerberos.authGSSClientStep(ctx,
                                                      str(response['payload']))
                  if result == -1:
                      raise OperationFailure('Unknown kerberos '
                                             'failure in step function.')
  
                  payload = kerberos.authGSSClientResponse(ctx) or ''
  
                  cmd = SON([('saslContinue', 1),
                             ('conversationId', response['conversationId']),
                             ('payload', payload)])
                  response = sock_info.command('$external', cmd)
  
                  if result == kerberos.AUTH_GSS_COMPLETE:
                      break
              else:
                  raise OperationFailure('Kerberos '
                                         'authentication failed to complete.')
  
              # Once the security context is established actually authenticate.
              # See RFC 4752, Section 3.1, last two paragraphs.
              if kerberos.authGSSClientUnwrap(ctx,
                                              str(response['payload'])) != 1:
                  raise OperationFailure('Unknown kerberos '
                                         'failure during GSS_Unwrap step.')
  
              if kerberos.authGSSClientWrap(ctx,
                                            kerberos.authGSSClientResponse(ctx),
                                            username) != 1:
                  raise OperationFailure('Unknown kerberos '
                                         'failure during GSS_Wrap step.')
  
              payload = kerberos.authGSSClientResponse(ctx)
              cmd = SON([('saslContinue', 1),
                         ('conversationId', response['conversationId']),
                         ('payload', payload)])
              sock_info.command('$external', cmd)
  
          finally:
              kerberos.authGSSClientClean(ctx)
  
      except kerberos.KrbError as exc:
          raise OperationFailure(str(exc))