On 06/12/2015 03:40 PM, Nathaniel McCallum wrote:
It doesn't apply again.

On Tue, 2015-06-09 at 15:55 +0200, Christian Heimes wrote:
On 2015-05-27 15:16, Christian Heimes wrote:
Hello,

here is my first patch for FreeIPA. The patch integrates python
-kdcproxy
for MS-KKDCP support (aka Kerberos over HTTPS).

https://www.freeipa.org/page/V4/KDC_Proxy

Ticket: https://fedorahosted.org/freeipa/ticket/4801
freeipa-cheimes-0001-2-Provide-Kerberos-over-HTTP-MS-KKDCP.patch
doesn't
apply anymore. The new patch is based on the current master.

Christian

--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code
So...I've been spoiled a bit by Gerrit. Here is what I just did to get them to apply:


cd freeipa
git clean -xdf .
#use the -3 to do 3 way merge
git am -3 ~/Documents/freeipa/patches/cheimes/freeipa-cheimes-0001-3-Provide-Kerberos-over-HTTP-MS-KKDCP.patch
@git status show conflicts in

    both modified:   install/share/Makefile.am
    both modified:   ipaplatform/base/paths.py

Which were due to this change and another making changes to the same section of the file, but they were "accept both" type conflicts

Updated patch is attached.  Christian, please confirm it is OK.






From 59c57ea2bfec59cac4a6b6dd35d794fef32c0b0f Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Thu, 21 May 2015 12:42:27 +0200
Subject: [PATCH] Provide Kerberos over HTTP (MS-KKDCP)

Add integration of python-kdcproxy into FreeIPA to support the MS
Kerberos KDC proxy protocol (MS-KKDCP), to allow KDC and KPASSWD
client requests over HTTP and HTTPS.

- freeipa-server now depends on python-kdcproxy >= 0.2.1. All kdcproxy
  dependencies are already satisfied.
- The service can be globally toggled with the boolean attribute
  ipaKDCproxyEnabled in cn=ipaConfig,cn=etc. The switch is supported by
  ipa config-mod --enable-kdcproxy.
- The installers and update create a new Apache config file
  ipa-kdc-proxy.conf that mounts a WSGI app at /KdcProxy. The app is run
  inside its own WSGI daemon group.
- The WSGI app at /KdcProxy is a WSGI wrapper, that checks the state of
  the switch. When ipaKDCproxyEnabled is FALSE, a HTTP 404 error is
  returned. For performance reasons the flag is only checked at start
  of the WSGI app. Apache must be reloaded or restarted to read the
  switch state again.
- The WSGI app uses the Apache principal to acquire a Kerberos ticket to
  perform GSSAPI bindings for the LDAP query of ipaKDCproxyEnabled.
- The WSGI wrapper script sets KDCPROXY_CONFIG=/etc/ipa/kdcproxy.conf,
  so that an existing config is not used.
- python-kdcproxy is configured to *not* use DNS SRV lookups. The
  location of KDC and KPASSWD servers are read from /etc/krb5.conf

Changes since patch 1:
- Further simplify krb ticket code
  Simo has pointed out that KRB5_CLIENT_KTNAME and MEMORY ccache are sufficient
  for the GSSAPI. http://k5wiki.kerberos.org/wiki/Projects/Keytab_initiation
- switch is now in ipaConfigString=kdcProxyEnabled of
  cn=KDC,cn=$FQDN,cn=masters,cn=ipa,cn=etc
- add service principal KDCPROXY
- add own keytab /etc/ipa/kdcproxy/kdcproxy.keytab
- add permission 'System: Read IPA Masters KDC Proxy'
- add privilege 'IPA Masters KDC Proxy Readers'
- add ipa-ldap-updater scripts to enable/disable KDC Proxy
- Create a separate user and group account
  The KDC Proxy WSGI app now uses a separate user account to run the
  daemon process. The keytab is only readable by that user, too.

https://www.freeipa.org/page/V4/KDC_Proxy

https://fedorahosted.org/freeipa/ticket/4801
---
 ACI.txt                                            |   4 +-
 API.txt                                            |   3 +-
 freeipa.spec.in                                    |  25 +++
 install/conf/Makefile.am                           |   1 +
 install/conf/ipa-kdc-proxy.conf                    |  14 ++
 install/conf/ipa.conf                              |   6 +-
 install/share/60ipaconfig.ldif                     |   4 +-
 install/share/Makefile.am                          |   2 +
 install/share/kdcproxy-disable.ldif                |   3 +
 install/share/kdcproxy-enable.ldif                 |   6 +
 install/share/kdcproxy.conf                        |   4 +
 install/share/kdcproxyshim.py                      | 161 +++++++++++++++++
 install/ui/src/freeipa/serverconfig.js             |   4 +
 install/updates/40-delegation.update               |   7 +
 install/updates/50-ipaconfig.update                |   4 +
 ipalib/plugins/config.py                           |   8 +-
 ipaplatform/base/paths.py                          |   4 +-
 ipaserver/install/ipa_backup.py                    |   1 +
 ipaserver/install/kdcproxyinstance.py              | 201 +++++++++++++++++++++
 .../install/plugins/update_managed_permissions.py  |  11 ++
 ipaserver/install/server/install.py                |   8 +-
 ipaserver/install/server/replicainstall.py         |   9 +-
 ipaserver/install/server/upgrade.py                |   8 +
 23 files changed, 488 insertions(+), 10 deletions(-)
 create mode 100644 install/conf/ipa-kdc-proxy.conf
 create mode 100644 install/share/kdcproxy-disable.ldif
 create mode 100644 install/share/kdcproxy-enable.ldif
 create mode 100644 install/share/kdcproxy.conf
 create mode 100644 install/share/kdcproxyshim.py
 create mode 100644 ipaserver/install/kdcproxyinstance.py

diff --git a/ACI.txt b/ACI.txt
index 60e9ebb10bc9b7266ff0d42a05d4d165d4ed2d55..8db2e20ec6aebca5c3ccea16d84136eaf335db9d 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -41,7 +41,7 @@ aci: (targetattr = "cn || description || ipacertprofilestoreissued")(targetfilte
 dn: cn=certprofiles,cn=ca,dc=ipa,dc=example
 aci: (targetattr = "cn || createtimestamp || description || entryusn || ipacertprofilestoreissued || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipacertprofile)")(version 3.0;acl "permission:System: Read Certificate Profiles";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=ipaconfig,cn=etc,dc=ipa,dc=example
-aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
+aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakdcproxyenabled || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=costemplates,cn=accounts,dc=ipa,dc=example
 aci: (targetfilter = "(objectclass=costemplate)")(version 3.0;acl "permission:System: Add Group Password Policy costemplate";allow (add) groupdn = "ldap:///cn=System: Add Group Password Policy costemplate,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=costemplates,cn=accounts,dc=ipa,dc=example
@@ -360,6 +360,8 @@ dn: cn=Domain Level,cn=ipa,cn=etc,dc=ipa,dc=example
 aci: (targetattr = "createtimestamp || entryusn || ipadomainlevel || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipadomainlevelconfig)")(version 3.0;acl "permission:System: Read Domain Level";allow (compare,read,search) userdn = "ldap:///all";;)
 dn: cn=masters,cn=ipa,cn=etc,dc=ipa,dc=example
 aci: (targetattr = "cn || createtimestamp || entryusn || ipaconfigstring || modifytimestamp || objectclass")(targetfilter = "(objectclass=nscontainer)")(version 3.0;acl "permission:System: Read IPA Masters";allow (compare,read,search) groupdn = "ldap:///cn=System: Read IPA Masters,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+dn: cn=masters,cn=ipa,cn=etc,dc=ipa,dc=example
+aci: (targetattr = "cn || createtimestamp || entryusn || ipaconfigstring || modifytimestamp || objectclass")(targetfilter = "(ipaConfigString=kdcProxyEnabled)")(version 3.0;acl "permission:System: Read IPA Masters KDC Proxy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read IPA Masters KDC Proxy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=config
 aci: (targetattr = "cn || createtimestamp || description || entryusn || modifytimestamp || nsds50ruv || nsds5beginreplicarefresh || nsds5debugreplicatimeout || nsds5flags || nsds5replicaabortcleanruv || nsds5replicaautoreferral || nsds5replicabackoffmax || nsds5replicabackoffmin || nsds5replicabinddn || nsds5replicabindmethod || nsds5replicabusywaittime || nsds5replicachangecount || nsds5replicachangessentsincestartup || nsds5replicacleanruv || nsds5replicacleanruvnotified || nsds5replicacredentials || nsds5replicaenabled || nsds5replicahost || nsds5replicaid || nsds5replicalastinitend || nsds5replicalastinitstart || nsds5replicalastinitstatus || nsds5replicalastupdateend || nsds5replicalastupdatestart || nsds5replicalastupdatestatus || nsds5replicalegacyconsumer || nsds5replicaname || nsds5replicaport || nsds5replicaprotocoltimeout || nsds5replicapurgedelay || nsds5replicareferral || nsds5replicaroot || nsds5replicasessionpausetime || nsds5replicastripattrs || nsds5replicatedattributelist || nsds5replicatedattributelisttotal || nsds5replicatimeout || nsds5replicatombstonepurgeinterval || nsds5replicatransportinfo || nsds5replicatype || nsds5replicaupdateinprogress || nsds5replicaupdateschedule || nsds5task || nsds7directoryreplicasubtree || nsds7dirsynccookie || nsds7newwingroupsyncenabled || nsds7newwinusersyncenabled || nsds7windowsdomain || nsds7windowsreplicasubtree || nsruvreplicalastmodified || nsstate || objectclass || onewaysync || winsyncdirectoryfilter || winsyncinterval || winsyncmoveaction || winsyncsubtreepair || winsyncwindowsfilter")(targetfilter = "(|(objectclass=nsds5Replica)(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement)(objectClass=nsMappingTree))")(version 3.0;acl "permission:System: Read Replication Agreements";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Replication Agreements,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=replication,cn=etc,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index 15356f7ee6330de0822e7582580d2d4f48ad261d..51b9e955c953ce4e868f90da9a979bbe015a2899 100644
--- a/API.txt
+++ b/API.txt
@@ -761,7 +761,7 @@ args: 0,1,1
 option: Str('version?', exclude='webui')
 output: Output('result', None, None)
 command: config_mod
-args: 0,25,3
+args: 0,26,3
 option: Str('addattr*', cli_name='addattr', exclude='webui')
 option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
 option: Str('delattr*', cli_name='delattr', exclude='webui')
@@ -772,6 +772,7 @@ option: Str('ipadefaultprimarygroup', attribute=True, autofill=False, cli_name='
 option: Str('ipagroupobjectclasses', attribute=True, autofill=False, cli_name='groupobjectclasses', csv=True, multivalue=True, required=False)
 option: IA5Str('ipagroupsearchfields', attribute=True, autofill=False, cli_name='groupsearch', multivalue=False, required=False)
 option: IA5Str('ipahomesrootdir', attribute=True, autofill=False, cli_name='homedirectory', multivalue=False, required=False)
+option: Bool('ipakdcproxyenabled', attribute=True, autofill=False, cli_name='enable_kdcproxy', multivalue=False, required=False)
 option: StrEnum('ipakrbauthzdata', attribute=True, autofill=False, cli_name='pac_type', csv=True, multivalue=True, required=False, values=(u'MS-PAC', u'PAD', u'nfs:NONE'))
 option: Int('ipamaxusernamelength', attribute=True, autofill=False, cli_name='maxusername', minvalue=1, multivalue=False, required=False)
 option: Bool('ipamigrationenabled', attribute=True, autofill=False, cli_name='enable_migration', multivalue=False, required=False)
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 8324bd21b3fa7be56cc2f0121269e6902c6ae307..109a49ff8fb4e12683fd40586b1bb8e01b22525e 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -22,6 +22,10 @@
 
 %define _hardened_build 1
 
+%define kdcproxy_user kdcproxy
+%define kdcproxy_group kdcproxy
+%define kdcproxy_home %{_sharedstatedir}/kdcproxy
+
 Name:           freeipa
 Version:        __VERSION__
 Release:        __RELEASE__%{?dist}
@@ -95,6 +99,7 @@ BuildRequires:  p11-kit-devel
 BuildRequires:  pki-base >= 10.2.4-1
 BuildRequires:  python-pytest-multihost >= 0.5
 BuildRequires:  python-pytest-sourceorder
+BuildRequires:  python-kdcproxy >= 0.2.1
 
 %description
 IPA is an integrated solution to provide centrally managed Identity (machine,
@@ -130,6 +135,7 @@ Requires: memcached
 Requires: python-memcached
 Requires: dbus-python
 Requires: systemd-units >= 38
+Requires(pre): shadow-utils
 Requires(pre): systemd-units
 Requires(post): systemd-units
 Requires: selinux-policy >= %{selinux_policy_version}
@@ -140,6 +146,7 @@ Requires: pki-kra >= 10.2.4-1
 Requires(preun): python systemd-units
 Requires(postun): python systemd-units
 Requires: python-dns >= 1.11.1
+Requires: python-kdcproxy >= 0.2.1
 Requires: zip
 Requires: policycoreutils >= 2.1.12-5
 Requires: tar
@@ -429,6 +436,7 @@ ln -s ../../../..%{_sysconfdir}/ipa/html/browserconfig.html \
 # So we can own our Apache configuration
 mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d/
 /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa.conf
+/bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf
 /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf
 /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
 mkdir -p %{buildroot}%{_usr}/share/ipa/html/
@@ -458,6 +466,10 @@ install daemons/dnssec/ipa-ods-exporter %{buildroot}%{_libexecdir}/ipa/ipa-ods-e
 # Web UI plugin dir
 mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins
 
+# KDC proxy config (kdcproxyshim.py sets KDCPROXY_CONFIG to load this file)
+mkdir -p %{buildroot}%{_sysconfdir}/ipa/kdcproxy/
+install -m 644 install/share/kdcproxy.conf %{buildroot}%{_sysconfdir}/ipa/kdcproxy/kdcproxy.conf
+
 # NOTE: systemd specific section
 mkdir -p %{buildroot}%{_tmpfilesdir}
 install -m 0644 init/systemd/ipa.conf.tmpfiles %{buildroot}%{_tmpfilesdir}/%{name}.conf
@@ -551,6 +563,13 @@ if [ -e /usr/sbin/ipa_kpasswd ]; then
 # END
 fi
 
+# create kdcproxy user
+getent group %{kdcproxy_group} >/dev/null || groupadd -r %{kdcproxy_group}
+getent passwd %{kdcproxy_user} >/dev/null || \
+    /usr/sbin/useradd -r -m -c "IPA KDC Proxy User" -s /sbin/nologin \
+    -g %{kdcproxy_group} -d %{kdcproxy_home} %{kdcproxy_user}
+exit 0
+
 %postun server-trust-ad
 if [ "$1" -ge "1" ]; then
     if [ "`readlink %{_sysconfdir}/alternatives/winbind_krb5_locator.so`" == "/dev/null" ]; then
@@ -686,6 +705,7 @@ fi
 %config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached
 %config(noreplace) %{_sysconfdir}/sysconfig/ipa-dnskeysyncd
 %config(noreplace) %{_sysconfdir}/sysconfig/ipa-ods-exporter
+%config(noreplace) %{_sysconfdir}/ipa/kdcproxy/kdcproxy.conf
 %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/
 %dir %attr(0700,root,root) %{_localstatedir}/run/ipa/
 %dir %attr(0700,apache,apache) %{_localstatedir}/run/httpd/ipa/
@@ -713,6 +733,7 @@ fi
 %attr(755,root,root) %{_libdir}/ipa/certmonger/*
 %dir %{_usr}/share/ipa
 %{_usr}/share/ipa/wsgi.py*
+%{_usr}/share/ipa/kdcproxyshim.py*
 %{_usr}/share/ipa/copy-schema-to-ca.py*
 %{_usr}/share/ipa/*.ldif
 %{_usr}/share/ipa/*.uldif
@@ -777,10 +798,13 @@ fi
 %config(noreplace) %{_sysconfdir}/ipa/html/browserconfig.html
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf
+%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf
 %{_usr}/share/ipa/ipa.conf
 %{_usr}/share/ipa/ipa-rewrite.conf
+%{_usr}/share/ipa/ipa-kdc-proxy.conf
 %{_usr}/share/ipa/ipa-pki-proxy.conf
+%{_usr}/share/ipa/kdcproxy.conf
 %ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt
 %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/configure.jar
 %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/kerberosauth.xpi
@@ -903,6 +927,7 @@ fi
 %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt
 %dir %attr(0755,root,root) %{_sysconfdir}/ipa/nssdb
 %dir %attr(0755,root,root) %{_sysconfdir}/ipa/dnssec
+%dir %attr(0755,root,root) %{_sysconfdir}/ipa/kdcproxy
 %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db
 %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db
 %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db
diff --git a/install/conf/Makefile.am b/install/conf/Makefile.am
index 65e25bc94682d85428ccfbcba87137c0d4edc3d0..cd064f3d30089cb95f40237bfcaa9b222a5e8d87 100644
--- a/install/conf/Makefile.am
+++ b/install/conf/Makefile.am
@@ -3,6 +3,7 @@ NULL =
 appdir = $(IPA_DATA_DIR)
 app_DATA =                              \
 	ipa.conf			\
+	ipa-kdc-proxy.conf		\
 	ipa-pki-proxy.conf		\
 	ipa-rewrite.conf		\
 	$(NULL)
diff --git a/install/conf/ipa-kdc-proxy.conf b/install/conf/ipa-kdc-proxy.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3e3a6cc32cf74bd80be9055af399d1827a464f45
--- /dev/null
+++ b/install/conf/ipa-kdc-proxy.conf
@@ -0,0 +1,14 @@
+WSGIDaemonProcess kdcproxy processes=2 threads=15 maximum-requests=5000 \
+  user=kdcproxy group=kdcproxy display-name=%{GROUP}
+WSGIImportScript /usr/share/ipa/kdcproxyshim.py \
+  process-group=kdcproxy application-group=kdcproxy
+WSGIScriptAlias /KdcProxy /usr/share/ipa/kdcproxyshim.py
+WSGIScriptReloading Off
+
+<Location "/KdcProxy">
+  Satisfy Any
+  Order Deny,Allow
+  Allow from all
+  WSGIProcessGroup kdcproxy
+  WSGIApplicationGroup kdcproxy
+</Location>
diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf
index 57de2f1a9543e1395f3eb46b045334f86cc8e79f..e2b602c8573078f517badac00a8c8c5bd593db28 100644
--- a/install/conf/ipa.conf
+++ b/install/conf/ipa.conf
@@ -41,9 +41,7 @@ WSGISocketPrefix /run/httpd/wsgi
 
 
 # Configure mod_wsgi handler for /ipa
-WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500
-WSGIProcessGroup ipa
-WSGIApplicationGroup ipa
+WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500 display-name=%{GROUP}
 WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa
 WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py
 WSGIScriptReloading Off
@@ -70,6 +68,8 @@ WSGIScriptReloading Off
   GssapiUseS4U2Proxy on
   Require valid-user
   ErrorDocument 401 /ipa/errors/unauthorized.html
+  WSGIProcessGroup ipa
+  WSGIApplicationGroup ipa
 </Location>
 
 # Turn off Apache authentication for sessions
diff --git a/install/share/60ipaconfig.ldif b/install/share/60ipaconfig.ldif
index 692690714aabad6b5e34328fe24cfab62bc0d70c..506058c809d8117a101eb4757c734e584c25950b 100644
--- a/install/share/60ipaconfig.ldif
+++ b/install/share/60ipaconfig.ldif
@@ -43,11 +43,13 @@ attributeTypes: ( 2.16.840.1.113730.3.8.3.23 NAME 'ipaCertificateSubjectBase' SY
 attributeTypes: (2.16.840.1.113730.3.8.3.16 NAME 'ipaConfigString' DESC 'Generic configuration stirng' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
 attributeTypes: ( 2.16.840.1.113730.3.8.3.26 NAME 'ipaSELinuxUserMapDefault' DESC 'Default SELinux user' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3')
 attributeTypes: ( 2.16.840.1.113730.3.8.3.27 NAME 'ipaSELinuxUserMapOrder' DESC 'Available SELinux user context ordering' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3')
+# ipaKDCProxyEnabled - if TRUE enable KDC Proxy service
+attributeTypes: ( 2.16.840.1.113730.3.8.3.28 NAME 'ipaKDCProxyEnabled' DESC 'Enable KDC over HTTPS proxy.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4.2' )
 ###############################################
 ##
 ## ObjectClasses
 ##
 ## ipaGuiConfig - GUI config parameters objectclass
-objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify $ ipaUserObjectClasses $ ipaGroupObjectClasses $ ipaDefaultEmailDomain $ ipaMigrationEnabled $ ipaCertificateSubjectBase $ ipaSELinuxUserMapDefault $ ipaSELinuxUserMapOrder $ ipaKrbAuthzData ) )
+objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify $ ipaUserObjectClasses $ ipaGroupObjectClasses $ ipaDefaultEmailDomain $ ipaMigrationEnabled $ ipaCertificateSubjectBase $ ipaSELinuxUserMapDefault $ ipaSELinuxUserMapOrder $ ipaKrbAuthzData $ ipaKDCProxyEnabled ) )
 ## ipaConfigObject - Generic config strings object holder
 objectClasses: (2.16.840.1.113730.3.8.4.13 NAME 'ipaConfigObject' DESC 'generic config object for IPA' AUXILIARY MAY ( ipaConfigString ) X-ORIGIN 'IPA v2' )
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index 53f0ecf01d5b401b3361ce5969b18dd713ad246f..a2ade5a8975300d99e0f6322c0b9fd39b8a12e1f 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -84,6 +84,8 @@ app_DATA =				\
 	sasl-mapping-fallback.ldif	\
 	schema-update.ldif		\
 	vault.update			\
+	kdcproxyshim.py			\
+	kdcproxy.conf			\
 	$(NULL)
 
 EXTRA_DIST =				\
diff --git a/install/share/kdcproxy-disable.ldif b/install/share/kdcproxy-disable.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..bfc0b72c18a0c1e83d3cf50e57dbb6f0e66f087d
--- /dev/null
+++ b/install/share/kdcproxy-disable.ldif
@@ -0,0 +1,3 @@
+# Disable MS-KKDCP protocol for the current host
+dn: cn=KDC,cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX
+remove:ipaConfigString:kdcProxyEnabled
diff --git a/install/share/kdcproxy-enable.ldif b/install/share/kdcproxy-enable.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..92297152fcd4c9cf77195ab4661d4eab4b98e0c0
--- /dev/null
+++ b/install/share/kdcproxy-enable.ldif
@@ -0,0 +1,6 @@
+# Enable MS-KKDCP protocol for the current host
+dn: cn=KDC,cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX
+default:objectClass: nsContainer
+default:objectClass: ipaConfigObject
+default:cn: KDC
+add: ipaConfigString: kdcProxyEnabled
diff --git a/install/share/kdcproxy.conf b/install/share/kdcproxy.conf
new file mode 100644
index 0000000000000000000000000000000000000000..530703d4aa67765a6a6a9cc82c81df7448c43608
--- /dev/null
+++ b/install/share/kdcproxy.conf
@@ -0,0 +1,4 @@
+[global]
+configs = mit
+use_dns = false
+
diff --git a/install/share/kdcproxyshim.py b/install/share/kdcproxyshim.py
new file mode 100644
index 0000000000000000000000000000000000000000..24becfe9a9b04e5d74f82a2d7d1aef019ee66c37
--- /dev/null
+++ b/install/share/kdcproxyshim.py
@@ -0,0 +1,161 @@
+# Authors:
+#   Christian Heimes <chei...@redhat.com>
+#
+# Copyright (C) 2015  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/>.
+#
+"""
+WSGI appliction for KDC Proxy
+"""
+import os
+from subprocess import check_call
+import sys
+
+from ipalib import api, errors
+from ipapython.ipa_log_manager import standard_logging_setup
+from ipapython.ipaldap import IPAdmin
+from ipapython.dn import DN
+from ipaplatform.paths import paths
+
+
+DEBUG = True
+TIME_LIMIT = 2
+
+
+class CheckError(Exception):
+    """An unrecoverable error has occured"""
+
+
+class KDCProxyConfig(object):
+    ipaconfig_flag = 'ipaKDCProxyEnabled'
+
+    def __init__(self, time_limit=TIME_LIMIT):
+        self.time_limit = time_limit
+        self.con = None
+        self.log = api.log
+        self.ldap_uri = api.env.ldap_uri
+        self.ccache = 'MEMORY:kdcproxy_%i' % os.getpid()
+        self.kdc_dn = DN(('cn', 'KDC'), ('cn', api.env.host),
+                         ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
+                         api.env.basedn)
+
+    def _kinit(self):
+        """Setup env for a krb5 ticket with own keytab"""
+        self.log.debug('Setup env for krb5 client keytab %s, ccache %s',
+                       paths.KDCPROXY_KEYTAB, self.ccache)
+        os.environ['KRB5CCNAME'] = self.ccache
+        os.environ['KRB5_CLIENT_KTNAME'] = paths.KDCPROXY_KEYTAB
+
+    def _kdestroy(self):
+        """Release krb5 ccache"""
+        self.log.debug('kdestroy %s', self.ccache)
+        try:
+            check_call([paths.KDESTROY, '-A', '-q', '-c', self.ccache])
+        finally:
+            del os.environ['KRB5CCNAME']
+            del os.environ['KRB5_CLIENT_KTNAME']
+
+    def _ldap_con(self):
+        """Establish LDAP connection"""
+        self.log.debug('ldap_uri: %s', self.ldap_uri)
+        try:
+            self.con = IPAdmin(ldap_uri=self.ldap_uri)
+            self.con.do_sasl_gssapi_bind()
+        except errors.NetworkError as e:
+            msg = 'Failed to get setting from dirsrv: %s' % e
+            self.log.exception(msg)
+            raise CheckError(msg)
+        except Exception as e:
+            msg = ('Unknown error while retrieving setting from %s: %s' %
+                   (self.ldap_uri, e))
+            self.log.exception(msg)
+            raise CheckError(msg)
+
+    def _find_entry(self, dn, attrs, filter, scope=IPAdmin.SCOPE_BASE):
+        """Find an LDAP entry, handles NotFound and Limit"""
+        try:
+            entries, truncated = self.con.find_entries(
+                filter, attrs, dn, scope, time_limit=self.time_limit)
+            if truncated:
+                raise errors.LimitsExceeded()
+        except errors.NotFound:
+            self.log.debug('Entry not found: %s', dn)
+            return None
+        except Exception as e:
+            msg = ('Unknown error while retrieving setting from %s: %s' %
+                   (self.ldap_uri, e))
+            self.log.exception(msg)
+            raise CheckError(msg)
+        return entries[0]
+
+    def host_enabled(self):
+        """Check replica specific flag"""
+        self.log.debug('Read settings from dn: %s', self.kdc_dn)
+        srcfilter = self.con.make_filter(
+            {'ipaConfigString': u'kdcProxyEnabled'}
+        )
+        entry = self._find_entry(self.kdc_dn, ['cn'], srcfilter)
+        self.log.debug('%s ipaConfigString: %s', self.kdc_dn, entry)
+        return entry is not None
+
+    def __enter__(self):
+        self._kinit()
+        self._ldap_con()
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self._kdestroy()
+        if self.con is not None:
+            self.con.unbind()
+            self.con = None
+
+
+def check_enabled(debug=DEBUG, time_limit=TIME_LIMIT):
+    # initialize API without file logging
+    if not api.isdone('bootstrap'):
+        api.bootstrap(context='kdcproxyshim', log=None, debug=debug)
+        standard_logging_setup(verbose=True, debug=debug)
+
+    with KDCProxyConfig(time_limit) as cfg:
+        if cfg.host_enabled():
+            api.log.info('kdcproxy ENABLED')
+            return True
+        else:
+            api.log.info('kdcproxy DISABLED')
+            return False
+
+
+ENABLED = check_enabled()
+
+# override config location
+if 'kdcproxy' in sys.modules:
+    raise CheckError('kdcproxy already imported')
+os.environ['KDCPROXY_CONFIG'] = paths.KDCPROXY_CONFIG
+import kdcproxy
+
+
+def application(environ, start_response):
+    if not ENABLED:
+        code = b'404 Not Found'
+        msg = b'KDC over HTTPS proxy service is not available.'
+        headers = [
+            ('Content-Type', 'text/plain; charset=utf-8'),
+            ('Content-Length', str(len(msg))),
+        ]
+        start_response(code, headers)
+        return [msg]
+    else:
+        return kdcproxy.application(environ, start_response)
diff --git a/install/ui/src/freeipa/serverconfig.js b/install/ui/src/freeipa/serverconfig.js
index efe1805698372b45afae38d1f9dd883034ee03c6..7eadcf612de5b7b82c6bbdf97f9714832483b72c 100644
--- a/install/ui/src/freeipa/serverconfig.js
+++ b/install/ui/src/freeipa/serverconfig.js
@@ -122,6 +122,10 @@ return {
                             name: 'ipakrbauthzdata',
                             $type: 'checkboxes',
                             options: IPA.create_options(['MS-PAC', 'PAD', 'nfs:NONE'])
+                        },
+                        {
+                            $type: 'checkbox',
+                            name: 'ipakdcproxyenabled'
                         }
                     ]
                 }
diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update
index bc0736c5b6c07747586a56c2cbde9596c7522d1c..cd6a3f3c520771f4a061b85e1e99fa10d809b808 100644
--- a/install/updates/40-delegation.update
+++ b/install/updates/40-delegation.update
@@ -185,6 +185,13 @@ dn: cn=masters,cn=ipa,cn=etc,$SUFFIX
 add:aci:(targetfilter = "(objectClass=nsContainer)")(targetattr = "cn || objectClass || ipaConfigString")(version 3.0; acl "Read IPA Masters"; allow (read, search, compare) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";;)
 add:aci:(targetfilter = "(objectClass=nsContainer)")(targetattr = "ipaConfigString")(version 3.0; acl "Modify IPA Masters"; allow (write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";;)
 
+dn: cn=IPA Masters KDC Proxy Readers,cn=privileges,cn=pbac,$SUFFIX
+default:objectClass: nestedgroup
+default:objectClass: groupofnames
+default:objectClass: top
+default:cn: IPA Masters KDC Proxy Readers
+default:description: Read KDC Proxy setting of IPA masters
+
 # PassSync
 dn: cn=PassSync Service,cn=privileges,cn=pbac,$SUFFIX
 default:objectClass: nestedgroup
diff --git a/install/updates/50-ipaconfig.update b/install/updates/50-ipaconfig.update
index 89a1726f4fb275868b18b9ab06c8498061f2e904..06ae371295db6310a924e810b39d5b9b6745f9f2 100644
--- a/install/updates/50-ipaconfig.update
+++ b/install/updates/50-ipaconfig.update
@@ -4,3 +4,7 @@ add:ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023
 add:ipaUserObjectClasses: ipasshuser
 remove:ipaConfigString:AllowLMhash
 add:objectClass: ipaUserAuthTypeClass
+
+addifnew:ipaKDCProxyEnabled: TRUE
+remove:aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
+add:aci: (targetattr = "cn || createtimestamp || entryusn || ipacertificatesubjectbase || ipaconfigstring || ipacustomfields || ipadefaultemaildomain || ipadefaultloginshell || ipadefaultprimarygroup || ipagroupobjectclasses || ipagroupsearchfields || ipahomesrootdir || ipakdcproxyenabled || ipakrbauthzdata || ipamaxusernamelength || ipamigrationenabled || ipapwdexpadvnotify || ipasearchrecordslimit || ipasearchtimelimit || ipaselinuxusermapdefault || ipaselinuxusermaporder || ipauserauthtype || ipauserobjectclasses || ipausersearchfields || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaguiconfig)")(version 3.0;acl "permission:System: Read Global Configuration";allow (compare,read,search) userdn = "ldap:///all";;)
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index 6267313d5e9af2d97f45f987115de143d7aa7915..ecd290461d7eee6d1a4480770489397af1e8a33d 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -96,7 +96,7 @@ class config(LDAPObject):
         'ipamigrationenabled', 'ipacertificatesubjectbase',
         'ipapwdexpadvnotify', 'ipaselinuxusermaporder',
         'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata',
-        'ipauserauthtype'
+        'ipauserauthtype', 'ipakdcproxyenabled',
     ]
     container_dn = DN(('cn', 'ipaconfig'), ('cn', 'etc'))
     permission_filter_objectclasses = ['ipaguiconfig']
@@ -117,6 +117,7 @@ class config(LDAPObject):
                 'ipasearchrecordslimit', 'ipasearchtimelimit',
                 'ipauserauthtype', 'ipauserobjectclasses',
                 'ipausersearchfields', 'ipacustomfields',
+                'ipakdcproxyenabled',
             },
         },
     }
@@ -231,6 +232,11 @@ class config(LDAPObject):
             values=(u'password', u'radius', u'otp', u'disabled'),
             csv=True,
         ),
+        Bool('ipakdcproxyenabled',
+            cli_name='enable_kdcproxy',
+            label=_('Enable KDC requests over HTTPS'),
+            doc=_('Enable KDC requests over HTTPS'),
+        ),
     )
 
     def get_dn(self, *keys, **kwargs):
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index e6b19181929b54f6d83701a0fdbc3c4a54364082..7d6d1ce388c0a527fecdde476f5b25771d005f70 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -49,6 +49,7 @@ class BasePathNamespace(object):
     ALIAS_CACERT_ASC = "/etc/httpd/alias/cacert.asc"
     ALIAS_PWDFILE_TXT = "/etc/httpd/alias/pwdfile.txt"
     HTTPD_CONF_D_DIR = "/etc/httpd/conf.d/"
+    HTTPD_IPA_KDC_PROXY_CONF = "/etc/httpd/conf.d/ipa-kdc-proxy.conf"
     HTTPD_IPA_PKI_PROXY_CONF = "/etc/httpd/conf.d/ipa-pki-proxy.conf"
     HTTPD_IPA_REWRITE_CONF = "/etc/httpd/conf.d/ipa-rewrite.conf"
     HTTPD_IPA_CONF = "/etc/httpd/conf.d/ipa.conf"
@@ -342,7 +343,8 @@ class BasePathNamespace(object):
     DB2LDIF = '/usr/sbin/db2ldif'
     BAK2DB = '/usr/sbin/bak2db'
     DB2BAK = '/usr/sbin/db2bak'
-
+    KDCPROXY_CONFIG = '/etc/ipa/kdcproxy/kdcproxy.conf'
+    KDCPROXY_KEYTAB = '/etc/ipa/kdcproxy/kdcproxy.keytab'
 
 
 path_namespace = BasePathNamespace
diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
index 01871c7b57a3e491cebf8fe81f040268992f1ada..36c95f3dd7b2f79d3b6c1bf6b5bc786e6c15c239 100644
--- a/ipaserver/install/ipa_backup.py
+++ b/ipaserver/install/ipa_backup.py
@@ -146,6 +146,7 @@ class Backup(admintool.AdminTool):
         paths.LIMITS_CONF,
         paths.HTTPD_PASSWORD_CONF,
         paths.IPA_KEYTAB,
+        paths.HTTPD_IPA_KDC_PROXY_CONF,
         paths.HTTPD_IPA_PKI_PROXY_CONF,
         paths.HTTPD_IPA_REWRITE_CONF,
         paths.HTTPD_NSS_CONF,
diff --git a/ipaserver/install/kdcproxyinstance.py b/ipaserver/install/kdcproxyinstance.py
new file mode 100644
index 0000000000000000000000000000000000000000..e927633c784e4758aed405242ad56c10ae759e53
--- /dev/null
+++ b/ipaserver/install/kdcproxyinstance.py
@@ -0,0 +1,201 @@
+# Authors: Christian Heimes <chei...@redhat.com>
+#
+# Copyright (C) 2015  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/>.
+#
+import os
+import pwd
+
+import ldap
+
+from ipalib import errors
+from ipalib.krb_utils import krb5_format_service_principal_name
+from ipapython import ipautil
+from ipapython import sysrestore
+from ipapython.dn import DN
+from ipapython.ipa_log_manager import root_logger
+from ipaplatform.paths import paths
+from ipaplatform import services
+
+import installutils
+import service
+
+
+class KDCProxyInstance(service.SimpleServiceInstance):
+    def __init__(self, fstore):
+        service.SimpleServiceInstance.__init__(self, "kdcproxy")
+        if fstore:
+            self.fstore = fstore
+        else:
+            self.fstore = sysrestore.FileStore(paths.SYSRESTORE)
+        # KDC proxy runs inside Apache HTTPD
+        self.service = None
+        self.httpd_service_name = 'httpd'
+        self.httpd_service = services.service(self.httpd_service_name)
+
+    # HTTPD
+    def start_httpd(self, instance_name="", capture_output=True, wait=True):
+        self.httpd_service.start(instance_name, capture_output=capture_output,
+                                 wait=wait)
+
+    def stop_httpd(self, instance_name="", capture_output=True):
+        self.httpd_service.stop(instance_name, capture_output=capture_output)
+
+    def restart_httpd(self, instance_name="", capture_output=True, wait=True):
+        self.httpd_service.restart(instance_name,
+                                   capture_output=capture_output,
+                                   wait=wait)
+
+    def is_httpd_running(self):
+        return self.httpd_service.is_running()
+
+    def is_httpd_enabled(self):
+        return self.httpd_service.is_enabled()
+
+    def is_configured(self):
+        return (os.path.isfile(paths.HTTPD_IPA_KDC_PROXY_CONF)
+                and os.path.isfile(paths.KDCPROXY_KEYTAB))
+
+    def disable(self):
+        pass
+
+    def create_instance(self, gensvc_name=None, fqdn=None, dm_password=None,
+                        ldap_suffix=None, realm=None):
+        assert gensvc_name == 'KDCPROXY'
+        self.gensvc_name = gensvc_name
+        self.fqdn = fqdn
+        self.dm_password = dm_password
+        self.suffix = ldap_suffix
+        self.realm = realm
+        self.principal = krb5_format_service_principal_name(
+            gensvc_name, self.fqdn, self.realm)
+        if not realm:
+            self.ldapi = False
+        self.sub_dict = dict(
+            REALM=realm,
+            FQDN=fqdn,
+        )
+        if not self.admin_conn:
+            self.ldap_connect()
+
+        self.step("creating a keytab for %s" % self.service_name,
+                  self.__create_kdcproxy_keytab)
+        self.step("Enable %s in KDC" % self.service_name,
+                  self.__enable_kdcproxy)
+        self.step("configuring httpd", self.__configure_http)
+        self.step("(re)starting %s " % self.httpd_service_name,
+                  self.__restart_httpd)
+        self.start_creation("Configuring %s" % self.service_name)
+
+    def __create_kdcproxy_keytab(self):
+        # create a principal for KDCPROXY
+        installutils.kadmin_addprinc(self.principal)
+        # create a keytab for the KDCPROXY principal
+        self.fstore.backup_file(paths.KDCPROXY_KEYTAB)
+        installutils.create_keytab(paths.KDCPROXY_KEYTAB, self.principal)
+        # ... and secure it
+        pent = pwd.getpwnam("kdcproxy")
+        os.chown(paths.KDCPROXY_KEYTAB, pent.pw_uid, pent.pw_gid)
+        os.chmod(paths.KDCPROXY_KEYTAB, 0400)
+
+        # move the principal to cn=services,cn=accounts
+        principal_dn = self.move_service(self.principal)
+        if principal_dn is None:
+            # already moved
+            principal_dn = DN(('krbprincipalname', self.principal),
+                              ('cn', 'services'), ('cn', 'accounts'),
+                              self.suffix)
+
+        # add a privilege to the KDCPROXY service principal, so it can read
+        # the ipaConfigString=kdcProxyEnabled attribute
+        privilege = DN(('cn', 'IPA Masters KDC Proxy Readers'),
+                       ('cn', 'privileges'), ('cn', 'pbac'), self.suffix)
+
+        mod = [(ldap.MOD_ADD, 'member', principal_dn)]
+        try:
+            self.admin_conn.modify_s(privilege, mod)
+        except ldap.TYPE_OR_VALUE_EXISTS:
+            pass
+        except Exception as e:
+            root_logger.critical("Could not modify principal's %s entry: %s",
+                                 principal_dn, str(e))
+            raise
+
+    def __enable_kdcproxy(self):
+        entry_name = DN(('cn', 'KDC'), ('cn', self.fqdn), ('cn', 'masters'),
+                        ('cn', 'ipa'), ('cn', 'etc'), self.suffix)
+        attr_name = 'kdcProxyEnabled'
+
+        try:
+            entry = self.admin_conn.get_entry(entry_name, ['ipaConfigString'])
+        except errors.NotFound:
+            pass
+        else:
+            if any(attr_name.lower() == val.lower()
+                   for val in entry.get('ipaConfigString', [])):
+                root_logger.debug("service KDCPROXY already enabled")
+                return
+
+            entry.setdefault('ipaConfigString', []).append(attr_name)
+            try:
+                self.admin_conn.update_entry(entry)
+            except errors.EmptyModlist:
+                root_logger.debug("service KDCPROXY already enabled")
+                return
+            except:
+                root_logger.debug("failed to enable service KDCPROXY")
+                raise
+
+            root_logger.debug("service KDCPROXY enabled")
+            return
+
+        entry = self.admin_conn.make_entry(
+            entry_name,
+            objectclass=["nsContainer", "ipaConfigObject"],
+            cn=['KDC'],
+            ipaconfigstring=[attr_name]
+        )
+
+        try:
+            self.admin_conn.add_entry(entry)
+        except errors.DuplicateEntry:
+            root_logger.debug("failed to add service KDCPROXY entry")
+            raise
+
+    def __configure_http(self):
+        target_fname = paths.HTTPD_IPA_KDC_PROXY_CONF
+        http_txt = ipautil.template_file(
+            ipautil.SHARE_DIR + "ipa-kdc-proxy.conf", self.sub_dict)
+        self.fstore.backup_file(target_fname)
+        with open(target_fname, 'w') as f:
+            f.write(http_txt)
+        os.chmod(target_fname, 0644)
+
+    def __restart_httpd(self):
+        self.backup_state("running", self.is_httpd_running())
+        self.restart_httpd()
+
+    def uninstall(self):
+        if self.is_configured():
+            self.print_msg("Unconfiguring %s" % self.service_name)
+
+        self.stop_httpd()
+
+        running = self.restore_state("running")
+        installutils.remove_file(paths.HTTPD_IPA_KDC_PROXY_CONF)
+
+        if running:
+            self.start_httpd()
diff --git a/ipaserver/install/plugins/update_managed_permissions.py b/ipaserver/install/plugins/update_managed_permissions.py
index 11765fba33342eb0168cfffa2f354f5ffc8cf4ef..2e57b83fb059bc72c6563cf56e6ba59196163d15 100644
--- a/ipaserver/install/plugins/update_managed_permissions.py
+++ b/ipaserver/install/plugins/update_managed_permissions.py
@@ -115,6 +115,17 @@ NONOBJECT_PERMISSIONS = {
         },
         'default_privileges': {'IPA Masters Readers'},
     },
+    'System: Read IPA Masters KDC Proxy': {
+        'replaces_global_anonymous_aci': True,
+        'ipapermlocation': DN('cn=masters,cn=ipa,cn=etc', api.env.basedn),
+        'ipapermtargetfilter': {'(ipaConfigString=kdcProxyEnabled)'},
+        'ipapermbindruletype': 'permission',
+        'ipapermright': {'read', 'search', 'compare'},
+        'ipapermdefaultattr': {
+            'cn', 'objectclass', 'ipaconfigstring',
+        },
+        'default_privileges': {'IPA Masters KDC Proxy Readers'},
+    },
     'System: Compat Tree ID View targets': {
         'replaces_global_anonymous_aci': True,
         'ipapermlocation':  api.env.basedn,
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index bde34851871f9b9f2bdf6dfecfd428755cc42e31..e0df9eaeda6b814f706adf85cc26af6be836492c 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -29,7 +29,7 @@ import ipaclient.ntpconf
 from ipaserver.install import (
     bindinstance, ca, cainstance, certs, dns, dsinstance, httpinstance,
     installutils, kra, krbinstance, memcacheinstance, ntpinstance,
-    otpdinstance, replication, service, sysupgrade)
+    otpdinstance, kdcproxyinstance, replication, service, sysupgrade)
 from ipaserver.install.installutils import (
     IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address,
     is_ipa_configured, load_pkcs12, read_password, verify_fqdn)
@@ -823,6 +823,11 @@ def install(installer):
             ca_is_configured=setup_ca)
     tasks.restore_context(paths.CACHE_IPA_SESSIONS)
 
+    # Create KDCProxyInstance
+    kdcproxy = kdcproxyinstance.KDCProxyInstance(fstore)
+    kdcproxy.create_instance('KDCPROXY', host_name, dm_password,
+                             ipautil.realm_to_suffix(realm_name))
+
     # Export full CA chain
     ca_db = certs.CertDB(realm_name)
     os.chmod(CACERT, 0644)
@@ -1065,6 +1070,7 @@ def uninstall(installer):
 
     dns.uninstall()
 
+    kdcproxyinstance.KDCProxyInstance(fstore).uninstall()
     httpinstance.HTTPInstance(fstore).uninstall()
     krbinstance.KrbInstance(fstore).uninstall()
     dsinstance.DsInstance(fstore=fstore).uninstall()
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 34580ce198b40f922ea984c1eea2dcd0c3aebb08..bd2c2ce98893b994ca4693c3f0bd95f1dd0358e7 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -25,7 +25,8 @@ from ipalib import api, certstore, constants, create_api, errors, x509
 import ipaclient.ntpconf
 from ipaserver.install import (
     bindinstance, ca, dns, dsinstance, httpinstance, installutils, kra,
-    krbinstance, memcacheinstance, ntpinstance, otpdinstance, service)
+    krbinstance, memcacheinstance, ntpinstance, otpdinstance, 
+    kdcproxyinstance, service)
 from ipaserver.install.installutils import create_replica_config
 from ipaserver.install.replication import (
     ReplicationManager, replica_conn_check)
@@ -579,6 +580,12 @@ def install(installer):
     otpd.create_instance('OTPD', config.host_name, config.dirman_password,
                          ipautil.realm_to_suffix(config.realm_name))
 
+    kdcproxy = kdcproxyinstance.KDCProxyInstance(fstore)
+    kdcproxy.create_instance('KDCPROXY',
+                             config.host_name,
+                             config.dirman_password,
+                             ipautil.realm_to_suffix(config.realm_name))
+
     # The DS instance is created before the keytab, add the SSL cert we
     # generated
     ds.add_cert_to_service()
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 306d1d27cda7a517117110ad3e6a760108f0fe19..8b74a75b49e5099c373f1a81dcbec97cab9dd4d9 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -31,6 +31,7 @@ from ipaserver.install import service
 from ipaserver.install import cainstance
 from ipaserver.install import certs
 from ipaserver.install import otpdinstance
+from ipaserver.install import kdcproxyinstance
 from ipaserver.install import sysupgrade
 from ipaserver.install import dnskeysyncinstance
 from ipaserver.install.upgradeinstance import IPAUpgrade
@@ -1403,6 +1404,13 @@ def upgrade_configuration():
                 dnskeysyncd.create_instance(fqdn, api.env.realm)
                 dnskeysyncd.start_dnskeysyncd()
 
+    # Install KDCProxy configuration file
+    kdcproxy = kdcproxyinstance.KDCProxyInstance(fstore)
+    if not kdcproxy.is_configured():
+        kdcproxy.create_instance('KDCPROXY', fqdn, None,
+                                 ipautil.realm_to_suffix(api.env.realm),
+                                 realm=api.env.realm)
+
     cleanup_kdc(fstore)
     cleanup_adtrust(fstore)
     setup_firefox_extension(fstore)
-- 
2.4.2

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to