summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-kdb
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-11-20 18:36:26 -0500
committerSimo Sorce <ssorce@redhat.com>2011-12-08 17:18:10 -0500
commit10264c9ea93fbecdc292643200d55274427ad3f7 (patch)
treef6bafdc6fef570aac43dc7ab53de8f81e7ffd67e /daemons/ipa-kdb
parent045c7c123eeb720173c19d5196b4fb5bb4cecbaa (diff)
downloadfreeipa-10264c9ea93fbecdc292643200d55274427ad3f7.tar.gz
freeipa-10264c9ea93fbecdc292643200d55274427ad3f7.tar.xz
freeipa-10264c9ea93fbecdc292643200d55274427ad3f7.zip
ipa-kdb: Add delgation access control support
Diffstat (limited to 'daemons/ipa-kdb')
-rw-r--r--daemons/ipa-kdb/Makefile.am1
-rw-r--r--daemons/ipa-kdb/README.s4u2proxy.txt124
-rw-r--r--daemons/ipa-kdb/ipa_kdb.c2
-rw-r--r--daemons/ipa-kdb/ipa_kdb.h7
-rw-r--r--daemons/ipa-kdb/ipa_kdb_delegation.c209
5 files changed, 342 insertions, 1 deletions
diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am
index c0a579bf4..77b92e8db 100644
--- a/daemons/ipa-kdb/Makefile.am
+++ b/daemons/ipa-kdb/Makefile.am
@@ -34,6 +34,7 @@ ipadb_la_SOURCES = \
ipa_kdb_principals.c \
ipa_kdb_pwdpolicy.c \
ipa_kdb_mspac.c \
+ ipa_kdb_delegation.c \
$(KRB5_UTIL_SRCS) \
$(NULL)
diff --git a/daemons/ipa-kdb/README.s4u2proxy.txt b/daemons/ipa-kdb/README.s4u2proxy.txt
new file mode 100644
index 000000000..92d71bbd3
--- /dev/null
+++ b/daemons/ipa-kdb/README.s4u2proxy.txt
@@ -0,0 +1,124 @@
+It is now possible to allow constrained delegation of credentials so
+that a service can impersonate a user when communicating with another
+service w/o requiring the user to actually forward their TGT.
+This makes for a much better method of delegating credentials as it
+prevents exposure of the short term secret of the user.
+
+I added a relatively simple access control method that allow the KDC to
+decide exactly which services are allowed to impersonate which users
+against other services. A simple grouping mechanism is used so that in
+large environments, clusters and otherwise classes of services can be
+much more easily managed.
+
+The grouping mechanism has been built so that lookup is highly optimized
+and is basically reduced to a single search that uses the derefernce
+control. Speed is very important in this case because KDC operations
+time out very quickly and unless we add a caching layer in ipa-kdb we
+must keep the number of searches down to avoid client timeouts.
+
+The grouping mechanism is very simple a groupOfPrincipals object is
+introduced, this Auxiliary class have a single optional attribute called
+memberPrincipal which is a string containing a principal name.
+
+A separate objectclass is also introduced called ipaKrb5DelegationACL,
+it is a subclass of groupOfPrincipals and is a Structural class.
+
+It has 2 additional optional attributes: ipaAllowedTarget and
+ipaAllowToImpersonate. They are both DNs.
+
+The memberPrincipal attribute in this class contains the list of
+principals that are being considered proxies[1]. That is: the
+principals of the services that want to impersonate client principals
+against other services.
+
+The ipaAllowedToImpersonate must point to a groupOfPrincipal based
+object that contains the list of client principals (normally these are
+user principals) that can be impersonated by this service.
+If the attribute is missing than the service is allowed to impersonate
+*any* user.
+
+The ipaAllowedTarget DN must point to a groupOfPrincipal based object
+that contains the list of service principals that the proxy service is
+allowed target when impersonating users. A target must be specified in
+order to allow a service to access it impersonating another principal.
+
+
+At the moment no wildcarding is implemented so services have to be
+explicitly listed in their respective groups.
+I have some idea of adding wildcard support at least for the
+ipaAllowedToImpersonate group in order to separate user principals by
+REALM. So you can say all users of REALM1 can be impersonated by this
+service but no users of REALM2.
+
+It is unclear how this wildcarding may be implemented, but it must be
+simple to avoid potentially very expensive computations every time a
+ticket for the target services is requested.
+
+I have briefly tested this patch by manually creating a few objects then
+using the kvno command to test that I could get a ldap ticket just using
+the HTTP credentials (in order to do this I had to allow also s4u2self
+operations for the HTTP service, but this is *not* generally required
+and it is *not* desired in the IPA framework implementation).
+
+This patchset does not contain any CLI or UI nor installation changes to
+create ipaKrb5DelegationACL obujects. It is indeed yet unclear where we
+want to store them (suggestions are welcome) and how/when we may want to
+expose this mechanism through UI/CLI for general usage.
+
+The initial intended usage is to allow us to move away from using
+forwarded TGTs in the IPA framework and instead use S4U2Proxy in order
+to access the ldap service. In order to do this some changes will need
+to be made in installation scripts and replica management scripts later.
+
+How to test:
+
+Create 2 objects like these:
+
+dn: cn=ipa-http-delegation,...
+objectClass: ipaKrb5DelegationACL
+objectClass: groupOfPrincipals
+cn: ipa-http-delegation
+memberPrincipal: HTTP/ipaserver.example.com@EXAMPLE.COM
+ipaAllowedTarget: cn=ipa-ldap-delegation-targets,...
+
+dn: cn=ipa-ldap-delegation-targets,...
+objectClass: groupOfPrincipals
+cn: ipa-ldap-delegation-targets
+memberPrincipal: ldap/ipaserver.example.com@EXAMPLE.COM
+
+
+In order to test with kvno which pretend to do s4u2self too you will
+need to allow the HTTP service to impersonate arbitrary users.
+
+This is done with:
+kdamin.local
+modprinc +ok_to_auth_as_delegate HTTP/ipaserver.example.com
+
+Then run kvno as follows:
+
+# Init credntials as HTTP
+kinit -kt /etc/httpd/conf/ipa.keytab HTTP/ipaserver.example.com
+
+# Perform S4U2Self
+kvno -U admin HTTP/ipaserver.example.com
+
+# Perform S4U2Proxy
+kvno -k /etc/httpd/conf/ipa.keytab -U admin -P HTTP/ipaserver.example.com
+ldap/ipaserver.example.com
+
+
+If this works it means you successfully impersonated the admin user with
+the HTTP service against the ldap service.
+
+Simo.
+
+
+[1]
+Note that here I use the term proxy in a different way than it is used in
+the krb interfaces. It may seem a bit confusing but I think people will
+understand it better this way.
+
+In this document 'client' connects to 'proxy' which impersonates 'client'
+against 'service'.
+In the Code/API the 'client' connects to 'server' which impersonates
+'client' against 'proxy'.
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index 05ee18720..ca266d546 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -458,6 +458,6 @@ kdb_vftabl kdb_function_table = {
NULL, /* check_policy_tgs */
NULL, /* audit_as_req */
NULL, /* refresh_config */
- NULL /* check_allowed_to_delegate */
+ ipadb_check_allowed_to_delegate /* check_allowed_to_delegate */
};
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 33b74a28a..2531d0328 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -223,3 +223,10 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
krb5_authdata ***signed_auth_data);
krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx);
+
+/* DELEGATION CHECKS */
+
+krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
+ krb5_const_principal client,
+ const krb5_db_entry *server,
+ krb5_const_principal proxy);
diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c
new file mode 100644
index 000000000..428e214b7
--- /dev/null
+++ b/daemons/ipa-kdb/ipa_kdb_delegation.c
@@ -0,0 +1,209 @@
+/*
+ * MIT Kerberos KDC database backend for FreeIPA
+ *
+ * Authors: Simo Sorce <ssorce@redhat.com>
+ *
+ * Copyright (C) 2011 Simo Sorce, Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipa_kdb.h"
+
+static char *acl_attrs[] = {
+ "objectClass",
+ "memberPrincipal",
+ NULL
+};
+
+static char *search_attrs[] = {
+ "ipaAllowToImpersonate",
+ "ipaAllowedTarget",
+ NULL
+};
+
+static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext,
+ char *srv_principal,
+ LDAPMessage **results)
+{
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr;
+ char *filter = NULL;
+ int ret;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ ret = asprintf(&filter,
+ "(&(objectclass=ipaKrb5DelegationACL)"
+ "(memberPrincipal=%s))", srv_principal);
+ if (ret == -1) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ /* == Search ACL info == */
+ kerr = ipadb_deref_search(ipactx, ipactx->base,
+ LDAP_SCOPE_SUBTREE, filter, acl_attrs,
+ search_attrs, acl_attrs, results);
+
+done:
+ free(filter);
+ return kerr;
+}
+
+static bool ipadb_match_member(char *princ, LDAPDerefRes *dres)
+{
+ LDAPDerefVal *dval;
+ int i;
+
+ for (dval = dres->attrVals; dval; dval = dval->next) {
+ if (strcasecmp(dval->type, "memberPrincipal") != 0) {
+ continue;
+ }
+
+ for (i = 0; dval->vals[i].bv_val != NULL; i++) {
+ /* FIXME: use utf8 aware comparison ? */
+ /* FIXME: support wildcards ? */
+ if (strncasecmp(princ, dval->vals[i].bv_val,
+ dval->vals[i].bv_len) == 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static krb5_error_code ipadb_match_acl(krb5_context kcontext,
+ LDAPMessage *results,
+ krb5_const_principal client,
+ krb5_const_principal target)
+{
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr = ENOENT;
+ LDAPMessage *lentry;
+ LDAPDerefRes *deref_results;
+ LDAPDerefRes *dres;
+ char *client_princ = NULL;
+ char *target_princ = NULL;
+ bool client_missing;
+ bool client_found;
+ bool target_found;
+ int ret;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ kerr = krb5_unparse_name(kcontext, client, &client_princ);
+ if (kerr != 0) {
+ goto done;
+ }
+ kerr = krb5_unparse_name(kcontext, target, &target_princ);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ lentry = ldap_first_entry(ipactx->lcontext, results);
+ if (!lentry) {
+ kerr = ENOENT;
+ goto done;
+ }
+
+ while (lentry) {
+ /* both client and target must be found in the same ACI */
+ client_missing = true;
+ client_found = false;
+ target_found = false;
+
+ ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry,
+ &deref_results);
+ switch (ret) {
+ case 0:
+ for (dres = deref_results; dres; dres = dres->next) {
+ if (strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
+ /* NOTE: client_missing is used to signal that the
+ * attribute was completely missing. This signals that
+ * ANY client is allowed to be impersonated.
+ * This logic is valid only for clients, not for targets */
+ client_missing = false;
+ client_found = ipadb_match_member(client_princ, dres);
+ }
+ if (strcasecmp(dres->derefAttr, "ipaAllowedTarget") == 0) {
+ target_found = ipadb_match_member(target_princ, dres);
+ }
+ }
+
+ ldap_derefresponse_free(deref_results);
+ break;
+ case ENOENT:
+ break;
+ default:
+ kerr = ret;
+ goto done;
+ }
+
+ if ((client_found == true || client_missing == true) &&
+ target_found == true) {
+ kerr = 0;
+ goto done;
+ }
+
+ lentry = ldap_next_entry(ipactx->lcontext, lentry);
+ }
+
+done:
+ krb5_free_unparsed_name(kcontext, client_princ);
+ krb5_free_unparsed_name(kcontext, target_princ);
+ return kerr;
+}
+
+/* Ok terminology is confusing here so read carefully:
+ * here 'proxy' is the service for which 'server' wants a ticket on behalf of
+ * 'client' */
+
+krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
+ krb5_const_principal client,
+ const krb5_db_entry *server,
+ krb5_const_principal proxy)
+{
+ krb5_error_code kerr;
+ char *srv_principal = NULL;
+ LDAPMessage *res = NULL;
+
+ kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &res);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = ipadb_match_acl(kcontext, res, client, proxy);
+ if (kerr) {
+ goto done;
+ }
+
+done:
+ krb5_free_unparsed_name(kcontext, srv_principal);
+ ldap_msgfree(res);
+ return kerr;
+}