From aad73fad601f576dd83b758f4448839b4e8e87df Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Mon, 20 Jul 2015 16:04:07 +0200 Subject: Port from python-krbV to python-gssapi python-krbV library is deprecated and doesn't work with python 3. Replacing all it's usages with python-gssapi. - Removed Backend.krb and KRB5_CCache classes They were wrappers around krbV classes that cannot really work without them - Added few utility functions for querying GSSAPI credentials in krb_utils module. They provide replacements for KRB5_CCache. - Merged two kinit_keytab functions - Changed ldap plugin connection defaults to match ipaldap - Unified getting default realm Using api.env.realm instead of krbV call Reviewed-By: Jan Cholasta Reviewed-By: Robbie Harwood Reviewed-By: Simo Sorce --- ipaserver/install/ipa_cacert_manage.py | 7 ++-- ipaserver/install/ipa_ldap_updater.py | 4 +-- ipaserver/install/ipa_otptoken_import.py | 7 ++-- ipaserver/install/ipa_winsync_migrate.py | 10 +++--- ipaserver/install/ldapupdate.py | 10 ++---- ipaserver/install/schemaupdate.py | 4 +-- ipaserver/install/server/upgrade.py | 3 +- ipaserver/plugins/join.py | 13 +------ ipaserver/plugins/ldap2.py | 60 +++++++++++++++++--------------- ipaserver/rpcserver.py | 25 ++++++------- 10 files changed, 62 insertions(+), 81 deletions(-) (limited to 'ipaserver') diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py index 34a931d1a..c991cafa1 100644 --- a/ipaserver/install/ipa_cacert_manage.py +++ b/ipaserver/install/ipa_cacert_manage.py @@ -23,7 +23,7 @@ from optparse import OptionGroup import base64 from nss import nss from nss.error import NSPRError -import krbV +import gssapi from ipapython import admintool, certmonger, ipautil from ipapython.dn import DN @@ -126,9 +126,8 @@ class CACertManage(admintool.AdminTool): password = self.options.password if not password: try: - ccache = krbV.default_context().default_ccache() - conn.connect(ccache=ccache) - except (krbV.Krb5Error, errors.ACIError): + conn.connect() + except (gssapi.exceptions.GSSError, errors.ACIError): pass else: return conn diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py index 2c4f28af4..8321c20a3 100644 --- a/ipaserver/install/ipa_ldap_updater.py +++ b/ipaserver/install/ipa_ldap_updater.py @@ -26,8 +26,6 @@ import os import sys -import krbV - from ipalib import api from ipapython import ipautil, admintool from ipaplatform.paths import paths @@ -100,7 +98,7 @@ class LDAPUpdater_Upgrade(LDAPUpdater): super(LDAPUpdater_Upgrade, self).run() options = self.options - realm = krbV.default_context().default_realm + realm = api.env.realm upgrade = IPAUpgrade(realm, self.files, schema_files=options.schema_files) diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py index 386ca4273..ae89f7e07 100644 --- a/ipaserver/install/ipa_otptoken_import.py +++ b/ipaserver/install/ipa_otptoken_import.py @@ -30,7 +30,7 @@ from lxml import etree import dateutil.parser import dateutil.tz import nss.nss as nss -import krbV +import gssapi from ipapython import admintool from ipalib import api, errors @@ -509,9 +509,8 @@ class OTPTokenImport(admintool.AdminTool): conn = ldap2(api) try: - ccache = krbV.default_context().default_ccache() - conn.connect(ccache=ccache) - except (krbV.Krb5Error, errors.ACIError): + conn.connect() + except (gssapi.exceptions.GSSError, errors.ACIError): raise admintool.ScriptError("Unable to connect to LDAP! Did you kinit?") try: diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py index 097b8c806..75d1dbe31 100644 --- a/ipaserver/install/ipa_winsync_migrate.py +++ b/ipaserver/install/ipa_winsync_migrate.py @@ -17,7 +17,7 @@ # along with this program. If not, see . # -import krbV +import gssapi import sys from ipalib import api @@ -321,12 +321,10 @@ class WinsyncMigrate(admintool.AdminTool): # Setup LDAP connection try: - ctx = krbV.default_context() - ccache = ctx.default_ccache() - api.Backend.ldap2.connect(ccache) + api.Backend.ldap2.connect() cls.ldap = api.Backend.ldap2 - except krbV.Krb5Error as e: - sys.exit("Must have Kerberos credentials to migrate Winsync users.") + except gssapi.exceptions.GSSError as e: + sys.exit("Must have Kerberos credentials to migrate Winsync users. Error: %s" % e) except errors.ACIError as e: sys.exit("Outdated Kerberos credentials. Use kdestroy and kinit to update your ticket.") except errors.DatabaseError as e: diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py index 1f3aca542..0444327aa 100644 --- a/ipaserver/install/ldapupdate.py +++ b/ipaserver/install/ldapupdate.py @@ -32,7 +32,6 @@ import pwd import fnmatch import re -import krbV import ldap from ipaserver.install import installutils @@ -272,13 +271,8 @@ class LDAPUpdate: if sub_dict.get("REALM"): self.realm = sub_dict["REALM"] else: - krbctx = krbV.default_context() - try: - self.realm = krbctx.default_realm - suffix = ipautil.realm_to_suffix(self.realm) - except krbV.Krb5Error: - self.realm = None - suffix = None + self.realm = api.env.realm + suffix = ipautil.realm_to_suffix(self.realm) if self.realm else None if suffix is not None: assert isinstance(suffix, DN) diff --git a/ipaserver/install/schemaupdate.py b/ipaserver/install/schemaupdate.py index 03edb6307..f98d0e949 100644 --- a/ipaserver/install/schemaupdate.py +++ b/ipaserver/install/schemaupdate.py @@ -20,9 +20,9 @@ import pprint import ldap.schema -import krbV import ipapython.version +from ipalib import api from ipapython.ipa_log_manager import log_mgr from ipapython.dn import DN from ipaserver.install.ldapupdate import connect @@ -106,7 +106,7 @@ def update_schema(schema_files, ldapi=False, dm_password=None,): SCHEMA_ELEMENT_CLASSES_KEYS = [x[0] for x in SCHEMA_ELEMENT_CLASSES] conn = connect(ldapi=ldapi, dm_password=dm_password, - realm=krbV.default_context().default_realm, + realm=api.env.realm, fqdn=installutils.get_fqdn()) old_schema = conn.schema diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py index f8a4ff282..cb92250e4 100644 --- a/ipaserver/install/server/upgrade.py +++ b/ipaserver/install/server/upgrade.py @@ -9,7 +9,6 @@ import pwd import fileinput import ConfigParser import sys -import krbV from ipalib import api import SSSDConfig @@ -1567,7 +1566,7 @@ def upgrade_check(options): def upgrade(): - realm = krbV.default_context().default_realm + realm = api.env.realm schema_files = [os.path.join(ipautil.SHARE_DIR, f) for f in dsinstance.ALL_SCHEMA_FILES] data_upgrade = IPAUpgrade(realm, schema_files=schema_files) diff --git a/ipaserver/plugins/join.py b/ipaserver/plugins/join.py index 3b668053c..7342117e7 100644 --- a/ipaserver/plugins/join.py +++ b/ipaserver/plugins/join.py @@ -21,8 +21,6 @@ Joining an IPA domain """ -import krbV - from ipalib import api from ipalib import Command, Str from ipalib import errors @@ -30,15 +28,6 @@ from ipalib import _ from ipaserver.install import installutils -def get_realm(): - """ - Returns the default kerberos realm configured for this server. - """ - krbctx = krbV.default_context() - - return unicode(krbctx.default_realm) - - def validate_host(ugettext, cn): """ Require at least one dot in the hostname (to support localhost.localdomain) @@ -66,7 +55,7 @@ class join(Command): takes_options = ( Str('realm', doc=_("The IPA realm"), - default_from=lambda: get_realm(), + default_from=lambda: api.env.realm, autofill=True, ), Str('nshardwareplatform?', diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index 68feee4f0..acaf45fdd 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -30,11 +30,12 @@ Backend plugin for LDAP. import os import pwd -import krbV import ldap as _ldap +from ipalib import krb_utils from ipapython.dn import DN -from ipapython.ipaldap import SASL_GSSAPI, LDAPClient +from ipapython.ipaldap import (LDAPClient, AUTOBIND_AUTO, AUTOBIND_ENABLED, + AUTOBIND_DISABLED) try: @@ -88,13 +89,14 @@ class ldap2(CrudBackend, LDAPClient): def create_connection(self, ccache=None, bind_dn=None, bind_pw='', tls_cacertfile=None, tls_certfile=None, tls_keyfile=None, - debug_level=0, autobind=False, serverctrls=None, clientctrls=None): + debug_level=0, autobind=AUTOBIND_AUTO, serverctrls=None, + clientctrls=None): """ Connect to LDAP server. Keyword arguments: ldapuri -- the LDAP server to connect to - ccache -- Kerberos V5 ccache object or name + ccache -- Kerberos ccache name bind_dn -- dn used to bind to the server bind_pw -- password used to bind to the server debug_level -- LDAP debug level option @@ -122,8 +124,6 @@ class ldap2(CrudBackend, LDAPClient): conn = self._conn with self.error_handler(): - if self.ldap_uri.startswith('ldapi://') and ccache: - conn.set_option(_ldap.OPT_HOST_NAME, self.api.env.host) minssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MIN) maxssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MAX) # Always connect with at least an SSF of 56, confidentiality @@ -134,33 +134,37 @@ class ldap2(CrudBackend, LDAPClient): if maxssf < minssf: conn.set_option(_ldap.OPT_X_SASL_SSF_MAX, minssf) - if ccache is not None: - if isinstance(ccache, krbV.CCache): - principal = ccache.principal().name - # Get a fully qualified CCACHE name (schema+name) - # As we do not use the krbV.CCache object later, - # we can safely overwrite it - ccache = "%(type)s:%(name)s" % dict(type=ccache.type, - name=ccache.name) - else: - principal = krbV.CCache(name=ccache, - context=krbV.default_context()).principal().name + ldapi = self.ldap_uri.startswith('ldapi://') - os.environ['KRB5CCNAME'] = ccache - self.gssapi_bind(server_controls=serverctrls, + if bind_pw: + self.simple_bind(bind_dn, bind_pw, + server_controls=serverctrls, client_controls=clientctrls) - setattr(context, 'principal', principal) - else: - # no kerberos ccache, use simple bind or external sasl - if autobind: - pent = pwd.getpwuid(os.geteuid()) - self.external_bind(pent.pw_name, + elif autobind != AUTOBIND_DISABLED and os.getegid() == 0 and ldapi: + try: + pw_name = pwd.getpwuid(os.geteuid()).pw_name + self.external_bind(pw_name, server_controls=serverctrls, client_controls=clientctrls) + except errors.NotFound: + if autobind == AUTOBIND_ENABLED: + # autobind was required and failed, raise + # exception that it failed + raise + else: + if ldapi: + with self.error_handler(): + conn.set_option(_ldap.OPT_HOST_NAME, self.api.env.host) + if ccache is None: + os.environ.pop('KRB5CCNAME', None) else: - self.simple_bind(bind_dn, bind_pw, - server_controls=serverctrls, - client_controls=clientctrls) + os.environ['KRB5CCNAME'] = ccache + + principal = krb_utils.get_principal(ccache_name=ccache) + + self.gssapi_bind(server_controls=serverctrls, + client_controls=clientctrls) + setattr(context, 'principal', principal) return conn diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py index 8fa097344..df75d98bb 100644 --- a/ipaserver/rpcserver.py +++ b/ipaserver/rpcserver.py @@ -30,7 +30,8 @@ import datetime import urlparse import json import traceback -from krbV import Krb5Error +import gssapi +import time import ldap.controls from pyasn1.type import univ, namedtype @@ -54,8 +55,8 @@ from ipalib.session import ( default_max_session_duration, krbccache_dir, krbccache_prefix) from ipalib.backend import Backend from ipalib.krb_utils import ( - KRB5_CCache, krb_ticket_expiration_threshold, krb5_format_principal_name, - krb5_format_service_principal_name) + krb_ticket_expiration_threshold, krb5_format_principal_name, + krb5_format_service_principal_name, get_credentials, get_credentials_if_valid) from ipapython import ipautil from ipaplatform.paths import paths from ipapython.version import VERSION @@ -593,8 +594,8 @@ class KerberosSession(object): session_data['ccache_data'] = load_ccache_data(ccache_name) # Set when the session will expire - cc = KRB5_CCache(ccache_name) - endtime = cc.endtime(self.api.env.host, self.api.env.realm) + creds = get_credentials(ccache_name=ccache_name) + endtime = creds.lifetime + time.time() self.update_session_expiration(session_data, endtime) # Store the session data now that it's been updated with the ccache @@ -789,15 +790,15 @@ class jsonserver_session(jsonserver, KerberosSession): ipa_ccache_name = bind_ipa_ccache(ccache_data) # Redirect to login if Kerberos credentials are expired - cc = KRB5_CCache(ipa_ccache_name) - if not cc.valid(self.api.env.host, self.api.env.realm): + creds = get_credentials_if_valid(ccache_name=ipa_ccache_name) + if not creds: self.debug('ccache expired, deleting session, need login') # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) return self.need_login(start_response) # Update the session expiration based on the Kerberos expiration - endtime = cc.endtime(self.api.env.host, self.api.env.realm) + endtime = creds.lifetime + time.time() self.update_session_expiration(session_data, endtime) # Store the session data in the per-thread context @@ -962,7 +963,7 @@ class login_password(Backend, KerberosSession, HTTP_Status): try: ipautil.kinit_keytab(armor_principal, paths.IPA_KEYTAB, armor_path) - except Krb5Error as e: + except gssapi.exceptions.GSSError as e: raise CCacheError(str(e)) # Format the user as a kerberos principal @@ -1229,15 +1230,15 @@ class xmlserver_session(xmlserver, KerberosSession): ipa_ccache_name = bind_ipa_ccache(ccache_data) # Redirect to /ipa/xml if Kerberos credentials are expired - cc = KRB5_CCache(ipa_ccache_name) - if not cc.valid(self.api.env.host, self.api.env.realm): + creds = get_credentials_if_valid(ccache_name=ipa_ccache_name) + if not creds: self.debug('xmlserver_session.__call_: ccache expired, deleting session, need login') # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) return self.need_login(start_response) # Update the session expiration based on the Kerberos expiration - endtime = cc.endtime(self.api.env.host, self.api.env.realm) + endtime = creds.lifetime + time.time() self.update_session_expiration(session_data, endtime) # Store the session data in the per-thread context -- cgit