Hi, Attached patch implements solution for https://fedorahosted.org/freeipa/ticket/1577.
With the patch applied to master, FreeIPA will be more forgiving for service principals requested with wrong character case. This is something supported by Active Directory where principals for services are case-insensitive and therefore HTTP/ or http/ point to the same service. In Kerberos LDAP schema, unfortunately, both krbPrincipalName and krbCanonicalName attributes are defined with exact match strategy, therefore, making impossible case-insensitive filtering. The patch solves this problem by introducing an attribute with case-insensitive matching strategy. Since there are several ways to create principals, we hook up at both FreeIPA management framework and KDC database plugin levels to intercept and maintain principal changes. We have decided only support case-insensitive searches for services where this is important and required feature. Services always have krbPrincipalName defined, and ipaKrbPrincipal object class will now be applied in addition to existing ones, to provide ipaKrbPrincipalAlias attribute (which is case-insensitive). Users will not get case-insensitive searches by default, though it is possible to introduce such feature to them as well by adding ipaKrbPrincipal class to the user and taking care of creating/maintaining the alias attribute synchronized with krbPrincipalName. Simo was originally against making case-insensitive aliases for users, though. Here is how it will look and act for services: ------------------------------------------------------------------ [root@m17 ~]# kvno cifs/M17.ipa.Local@IPA.LOCAL cifs/M17.ipa.Local@IPA.LOCAL: kvno = 1 [root@m17 ~]# kvno CIFS/M17.ipa.Local@IPA.LOCAL CIFS/M17.ipa.Local@IPA.LOCAL: kvno = 1 [root@m17 ~]# klist Ticket cache: FILE:/tmp/krb5cc_0 Default principal: admin@IPA.LOCAL Valid starting Expires Service principal 03/29/12 14:38:57 03/30/12 14:38:55 krbtgt/IPA.LOCAL@IPA.LOCAL 03/29/12 14:39:05 03/30/12 14:38:55 HTTP/m17.ipa.local@IPA.LOCAL 03/29/12 15:00:51 03/30/12 14:38:55 ldap/m17.ipa.local@IPA.LOCAL 03/29/12 15:08:02 03/30/12 14:38:55 krbtgt/IPA.LocAl@IPA.LOCAL 03/29/12 15:08:19 03/30/12 14:38:55 cifs/M17.ipa.Local@IPA.LOCAL 03/29/12 15:08:48 03/30/12 14:38:55 CIFS/M17.ipa.Local@IPA.LOCAL ------------------------------------------------------------------ Please note that case-insensitive realm search is still not supported, even if you enable DNS resolution of realms and KDCs: [root@m17 ~]# kvno cIfS/m17.ipa.local@ipa.LoCaL kvno: Cannot find KDC for requested realm while getting credentials for cIfS/m17.ipa.local@ipa.LoCaL This is due to some krbtgt/realm@REALM searches performed in KDC without allowing for principal aliases and therefore no chance to our case-insensitive searches to kick in. Additional discussion is needed, I think, if we want to support case-insensitive realms. -- / Alexander Bokovoy
>From 7d0c8669df0da44c9056581bd29af3f0abec58d4 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy <aboko...@redhat.com> Date: Mon, 26 Mar 2012 14:23:42 +0300 Subject: [PATCH 6/9] Perform case-insensitive searches for principals on TGS requests We want to always resolve TGS requests even if the user mistakenly sends a request for a service ticket where the fqdn part contain upper case letters. The actual implementation follows hints set by KDC. When AP_REQ is done, KDC sets KRB5_FLAG_ALIAS_OK and we obey it when looking for principals on TGS requests. https://fedorahosted.org/freeipa/ticket/1577 --- daemons/ipa-kdb/ipa_kdb_principals.c | 73 ++++++++++++++++++++++++---------- install/share/61kerberos-ipav3.ldif | 3 ++ install/share/Makefile.am | 1 + install/updates/10-60basev3.update | 2 + ipalib/plugins/service.py | 7 +++- ipaserver/install/dsinstance.py | 1 + 6 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 install/share/61kerberos-ipav3.ldif diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index 1432619..2e190a1 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -22,6 +22,16 @@ #include "ipa_kdb.h" +/* + * During TGS request search by ipaKrbPrincipalName (case-insensitive) + * and krbPrincipalName (case-sensitive) + */ +#define PRINC_TGS_SEARCH_FILTER "(&(|(objectclass=krbprincipalaux)" \ + "(objectclass=krbprincipal)" \ + "(objectclass=ipakrbprincipal))" \ + "(|(ipakrbprincipalalias=%s)" \ + "(krbprincipalname=%s)))" + #define PRINC_SEARCH_FILTER "(&(|(objectclass=krbprincipalaux)" \ "(objectclass=krbprincipal))" \ "(krbprincipalname=%s))" @@ -29,6 +39,7 @@ static char *std_principal_attrs[] = { "krbPrincipalName", "krbCanonicalName", + "ipaKrbPrincipalAlias", "krbUPEnabled", "krbPrincipalKey", "krbTicketPolicyReference", @@ -73,6 +84,7 @@ static char *std_principal_obj_classes[] = { "krbprincipal", "krbprincipalaux", "krbTicketPolicyAux", + "ipakrbprincipal", NULL }; @@ -636,13 +648,14 @@ done: } static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, - char *search_expr, + unsigned int flags, + char *principal, LDAPMessage **result) { krb5_error_code kerr; char *src_filter = NULL; - char *esc_search_expr = NULL; - int ret; + char *esc_original_princ = NULL; + int ret, i; if (!ipactx->lcontext) { ret = ipadb_get_connection(ipactx); @@ -654,13 +667,19 @@ static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, /* escape filter but do not touch '*' as this function accepts * wildcards in names */ - esc_search_expr = ipadb_filter_escape(search_expr, false); - if (!esc_search_expr) { + esc_original_princ = ipadb_filter_escape(principal, false); + if (!esc_original_princ) { kerr = KRB5_KDB_INTERNAL_ERROR; goto done; } - ret = asprintf(&src_filter, PRINC_SEARCH_FILTER, esc_search_expr); + if (flags & KRB5_KDB_FLAG_ALIAS_OK) { + ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER, + esc_original_princ, esc_original_princ); + } else { + ret = asprintf(&src_filter, PRINC_SEARCH_FILTER, esc_original_princ); + } + if (ret == -1) { kerr = KRB5_KDB_INTERNAL_ERROR; goto done; @@ -673,7 +692,7 @@ static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, done: free(src_filter); - free(esc_search_expr); + free(esc_original_princ); return kerr; } @@ -713,9 +732,12 @@ static krb5_error_code ipadb_find_principal(krb5_context kcontext, /* we need to check for a strict match as a '*' in the name may have * caused the ldap server to return multiple entries */ for (i = 0; vals[i]; i++) { - /* FIXME: use case insensitive compare and tree as alias ?? */ - if (strcmp(vals[i]->bv_val, (*principal)) == 0) { - found = true; + /* KDC will accept aliases when doing TGT lookup (ref_tgt_again in do_tgs_req.c */ + /* Use case-insensitive comparison in such cases */ + if ((flags & KRB5_KDB_FLAG_ALIAS_OK) != 0) { + found = (strcasecmp(vals[i]->bv_val, (*principal)) == 0); + } else { + found = (strcmp(vals[i]->bv_val, (*principal)) == 0); } } @@ -731,11 +753,15 @@ static krb5_error_code ipadb_find_principal(krb5_context kcontext, continue; } - /* FIXME: use case insensitive compare and treat as alias ?? */ - if (strcmp(vals[0]->bv_val, (*principal)) != 0 && - !(flags & KRB5_KDB_FLAG_ALIAS_OK)) { + /* Again, if aliases are accepted by KDC, use case-insensitive comparison */ + if ((flags & KRB5_KDB_FLAG_ALIAS_OK) != 0) { + found = (strcasecmp(vals[0]->bv_val, (*principal)) == 0); + } else { + found = (strcmp(vals[0]->bv_val, (*principal)) == 0); + } + + if (!found) { /* search does not allow aliases */ - found = false; ldap_value_free_len(vals); continue; } @@ -883,7 +909,7 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, goto done; } - kerr = ipadb_fetch_principals(ipactx, principal, &res); + kerr = ipadb_fetch_principals(ipactx, flags, principal, &res); if (kerr != 0) { goto done; } @@ -1398,6 +1424,11 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext, if (kerr) { goto done; } + kerr = ipadb_get_ldap_mod_str(imods, "ipaKrbPrincipalAlias", + principal, mod_op); + if (kerr) { + goto done; + } } /* KADM5_PRINC_EXPIRE_TIME */ @@ -1735,13 +1766,13 @@ static krb5_error_code ipadb_add_principal(krb5_context kcontext, goto done; } - kerr = ipadb_entry_to_mods(kcontext, imods, - entry, principal, LDAP_MOD_ADD); + kerr = ipadb_entry_default_attrs(imods); if (kerr != 0) { goto done; } - kerr = ipadb_entry_default_attrs(imods); + kerr = ipadb_entry_to_mods(kcontext, imods, + entry, principal, LDAP_MOD_ADD); if (kerr != 0) { goto done; } @@ -1779,7 +1810,7 @@ static krb5_error_code ipadb_modify_principal(krb5_context kcontext, goto done; } - kerr = ipadb_fetch_principals(ipactx, principal, &res); + kerr = ipadb_fetch_principals(ipactx, 0, principal, &res); if (kerr != 0) { goto done; } @@ -1930,7 +1961,7 @@ krb5_error_code ipadb_delete_principal(krb5_context kcontext, goto done; } - kerr = ipadb_fetch_principals(ipactx, principal, &res); + kerr = ipadb_fetch_principals(ipactx, 0, principal, &res); if (kerr != 0) { goto done; } @@ -1982,7 +2013,7 @@ krb5_error_code ipadb_iterate(krb5_context kcontext, } /* fetch list of principal matching filter */ - kerr = ipadb_fetch_principals(ipactx, match_entry, &res); + kerr = ipadb_fetch_principals(ipactx, 0, match_entry, &res); if (kerr != 0) { goto done; } diff --git a/install/share/61kerberos-ipav3.ldif b/install/share/61kerberos-ipav3.ldif new file mode 100644 index 0000000..dcdaa5d --- /dev/null +++ b/install/share/61kerberos-ipav3.ldif @@ -0,0 +1,3 @@ +dn: cn=schema +attributeTypes: (2.16.840.1.113730.3.8.11.32 NAME 'ipaKrbPrincipalAlias' DESC 'IPA principal alias' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') +objectClasses: (2.16.840.1.113730.3.8.12.8 NAME 'ipaKrbPrincipal' SUP krbPrincipalAux AUXILIARY MUST ( krbPrincipalName $ ipaKrbPrincipalAlias ) X-ORIGIN 'IPA v3' ) diff --git a/install/share/Makefile.am b/install/share/Makefile.am index 81fd0dc..68c98e0 100644 --- a/install/share/Makefile.am +++ b/install/share/Makefile.am @@ -9,6 +9,7 @@ app_DATA = \ 60basev2.ldif \ 60basev3.ldif \ 60ipadns.ldif \ + 61kerberos-ipav3.ldif \ 65ipasudo.ldif \ anonymous-vlv.ldif \ bootstrap-template.ldif \ diff --git a/install/updates/10-60basev3.update b/install/updates/10-60basev3.update index 796eb16..96d012c 100644 --- a/install/updates/10-60basev3.update +++ b/install/updates/10-60basev3.update @@ -4,3 +4,5 @@ add:attributeTypes: ( 2.16.840.1.113730.3.8.11.21 NAME 'ipaAllowToImpersonate' D add:attributeTypes: ( 2.16.840.1.113730.3.8.11.22 NAME 'ipaAllowedTarget' DESC 'Target principals alowed to get a ticket for' SUP distinguishedName X-ORIGIN 'IPA-v3') add:objectClasses: (2.16.840.1.113730.3.8.12.6 NAME 'groupOfPrincipals' SUP top AUXILIARY MUST ( cn ) MAY ( memberPrincipal ) X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.7 NAME 'ipaKrb5DelegationACL' SUP groupOfPrincipals STRUCTURAL MAY ( ipaAllowToImpersonate $$ ipaAllowedTarget ) X-ORIGIN 'IPA v3' ) +add:attributeTypes: (2.16.840.1.113730.3.8.11.32 NAME 'ipaKrbPrincipalAlias' DESC 'IPA principal alias' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') +add:objectClasses: (2.16.840.1.113730.3.8.12.8 NAME 'ipaKrbPrincipal' SUP krbPrincipalAux AUXILIARY MUST ( krbPrincipalName $$ ipaKrbPrincipalAlias ) X-ORIGIN 'IPA v3' ) diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index 7c563b3..d2ddd4e 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -221,7 +221,7 @@ class service(LDAPObject): object_name_plural = _('services') object_class = [ 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', - 'ipaservice', 'pkiuser' + 'ipaservice', 'pkiuser', 'ipakrbprincipal' ] search_attributes = ['krbprincipalname', 'managedby'] default_attributes = ['krbprincipalname', 'usercertificate', 'managedby'] @@ -293,6 +293,11 @@ class service_add(LDAPCreate): if not 'managedby' in entry_attrs: entry_attrs['managedby'] = hostresult['dn'] + # Enforce ipaKrbPrincipalAlias to aid case-insensitive searches + # as krbPrincipalName/krbCanonicalName are case-sensitive in Kerberos + # schema + entry_attrs['ipakrbprincipalalias'] = keys[-1] + return dn api.register(service_add) diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py index e549e13..5d40941 100644 --- a/ipaserver/install/dsinstance.py +++ b/ipaserver/install/dsinstance.py @@ -359,6 +359,7 @@ class DsInstance(service.Service): "60basev2.ldif", "60basev3.ldif", "60ipadns.ldif", + "61kerberos-ipav3.ldif", "65ipasudo.ldif"): target_fname = schema_dirname(self.serverid) + schema_fname shutil.copyfile(ipautil.SHARE_DIR + schema_fname, target_fname) -- 1.7.9.3
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel