summaryrefslogtreecommitdiffstats
path: root/ipaserver
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2016-12-02 06:48:35 -0500
committerJan Cholasta <jcholast@redhat.com>2017-02-15 07:13:37 +0100
commitb6741d81e187fc84177c12ef8ad900d3b5cda6a4 (patch)
tree32e5c708bb5f5c2d3552d34c881facc890ee4cf8 /ipaserver
parentb109f5d850ce13585d4392ca48896dc069a746e5 (diff)
downloadfreeipa-b6741d81e187fc84177c12ef8ad900d3b5cda6a4.tar.gz
freeipa-b6741d81e187fc84177c12ef8ad900d3b5cda6a4.tar.xz
freeipa-b6741d81e187fc84177c12ef8ad900d3b5cda6a4.zip
Use Anonymous user to obtain FAST armor ccache
The anonymous user allows the framework to obtain an armor ccache without relying on usable credentials, either via a keytab or a pkinit and public certificates. This will be needed once the HTTP keytab is moved away for privilege separation. https://fedorahosted.org/freeipa/ticket/5959 Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'ipaserver')
-rw-r--r--ipaserver/install/httpinstance.py13
-rw-r--r--ipaserver/install/krbinstance.py5
-rw-r--r--ipaserver/install/server/upgrade.py1
-rw-r--r--ipaserver/install/service.py16
-rw-r--r--ipaserver/plugins/pkinit.py3
-rw-r--r--ipaserver/rpcserver.py29
6 files changed, 41 insertions, 26 deletions
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index a4e895cb4..d07b32253 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -43,6 +43,7 @@ import ipapython.errors
from ipaserver.install import sysupgrade
from ipalib import api
from ipalib import errors
+from ipalib.constants import ANON_USER
from ipaplatform.constants import constants
from ipaplatform.tasks import tasks
from ipaplatform.paths import paths
@@ -167,6 +168,7 @@ class HTTPInstance(service.Service):
self.step("adding URL rewriting rules", self.__add_include)
self.step("configuring httpd", self.__configure_http)
self.step("setting up httpd keytab", self._request_service_keytab)
+ self.step("retrieving anonymous keytab", self.request_anon_keytab)
self.step("setting up ssl", self.__setup_ssl)
if self.ca_is_configured:
self.step("configure certmonger for renewals",
@@ -333,6 +335,17 @@ class HTTPInstance(service.Service):
os.chown(nss_path, 0, pent.pw_gid)
tasks.restore_context(nss_path)
+ def request_anon_keytab(self):
+ parent = os.path.dirname(paths.ANON_KEYTAB)
+ if not os.path.exists(parent):
+ os.makedirs(parent, 0o755)
+ self.run_getkeytab(self.api.env.ldap_uri, paths.ANON_KEYTAB, ANON_USER)
+
+ pent = pwd.getpwnam(self.service_user)
+ os.chmod(parent, 0o700)
+ os.chown(parent, pent.pw_uid, pent.pw_gid)
+ os.chown(paths.ANON_KEYTAB, pent.pw_uid, pent.pw_gid)
+
def __setup_ssl(self):
db = certs.CertDB(self.realm, subject_base=self.subject_base)
if self.pkcs12_info:
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index b52b0c3f9..44b382126 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -33,6 +33,7 @@ from ipaserver.install import installutils
from ipapython import ipautil
from ipapython import kernel_keyring
from ipalib import api
+from ipalib.constants import ANON_USER
from ipalib.install import certmonger
from ipapython.ipa_log_manager import root_logger
from ipapython.dn import DN
@@ -381,13 +382,13 @@ class KrbInstance(service.Service):
shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM)
def get_anonymous_principal_name(self):
- princ = "WELLKNOWN/ANONYMOUS"
- return "%s@%s" % (princ, self.realm)
+ return "%s@%s" % (ANON_USER, self.realm)
def add_anonymous_principal(self):
# Create the special anonymous principal
princ_realm = self.get_anonymous_principal_name()
installutils.kadmin_addprinc(princ_realm)
+ self._ldap_mod("anon-princ-aci.ldif", self.sub_dict)
def __convert_to_gssapi_replication(self):
repl = replication.ReplicationManager(self.realm,
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index c7f0f9f44..80abeba53 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1757,6 +1757,7 @@ def upgrade_configuration():
krb.stop()
krb.start()
enable_anonymous_principal(krb)
+ http.request_anon_keytab()
if not ds_running:
ds.stop(ds_serverid)
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index b80044f4b..fe6defc9c 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -539,7 +539,7 @@ class Service(object):
except errors.DuplicateEntry:
pass
- def _run_getkeytab(self):
+ def run_getkeytab(self, ldap_uri, keytab, principal, retrieve=False):
"""
backup and remove old service keytab (if present) and fetch a new one
using ipa-getkeytab. This assumes that the service principal is already
@@ -549,16 +549,15 @@ class Service(object):
* self.dm_password is not none, then DM credentials are used to
fetch keytab
"""
- self.fstore.backup_file(self.keytab)
+ self.fstore.backup_file(keytab)
try:
- os.unlink(self.keytab)
+ os.unlink(keytab)
except OSError:
pass
- ldap_uri = self.api.env.ldap_uri
args = [paths.IPA_GETKEYTAB,
- '-k', self.keytab,
- '-p', self.principal,
+ '-k', keytab,
+ '-p', principal,
'-H', ldap_uri]
nolog = tuple()
@@ -570,6 +569,9 @@ class Service(object):
'-w', self.dm_password])
nolog += (self.dm_password,)
+ if retrieve:
+ args.extend(['-r'])
+
ipautil.run(args, nolog=nolog)
def _request_service_keytab(self):
@@ -580,7 +582,7 @@ class Service(object):
"name, keytab, and username")
self._add_service_principal()
- self._run_getkeytab()
+ self.run_getkeytab(self.api.env.ldap_uri, self.keytab, self.principal)
pent = pwd.getpwnam(self.service_user)
os.chown(self.keytab, pent.pw_uid, pent.pw_gid)
diff --git a/ipaserver/plugins/pkinit.py b/ipaserver/plugins/pkinit.py
index 0ad4b8571..b6b3f3882 100644
--- a/ipaserver/plugins/pkinit.py
+++ b/ipaserver/plugins/pkinit.py
@@ -22,6 +22,7 @@ from ipalib import Str
from ipalib import Object, Command
from ipalib import _
from ipalib.plugable import Registry
+from ipalib.constants import ANON_USER
from ipapython.dn import DN
__doc__ = _("""
@@ -71,7 +72,7 @@ def valid_arg(ugettext, action):
class pkinit_anonymous(Command):
__doc__ = _('Enable or Disable Anonymous PKINIT.')
- princ_name = 'WELLKNOWN/ANONYMOUS@%s' % api.env.realm
+ princ_name = '%s@%s' % (ANON_USER, api.env.realm)
default_dn = DN(('krbprincipalname', princ_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn)
takes_args = (
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 34106ee86..357e836f9 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -42,7 +42,7 @@ from six.moves.xmlrpc_client import Fault
from ipalib import plugable, errors
from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES
from ipalib.frontend import Local
-from ipalib.install.kinit import kinit_keytab, kinit_password
+from ipalib.install.kinit import kinit_armor, kinit_password
from ipalib.backend import Executioner
from ipalib.errors import (PublicError, InternalError, JSONError,
CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError,
@@ -56,7 +56,7 @@ from ipaserver.plugins.ldap2 import ldap2
from ipalib.backend import Backend
from ipalib.krb_utils import (
krb5_format_principal_name,
- krb5_format_service_principal_name, get_credentials_if_valid)
+ get_credentials_if_valid)
from ipapython import ipautil
from ipaplatform.paths import paths
from ipapython.version import VERSION
@@ -945,20 +945,18 @@ class login_password(Backend, KerberosSession):
return result
def kinit(self, user, realm, password, ccache_name):
- # get http service ccache as an armor for FAST to enable OTP authentication
- armor_principal = str(krb5_format_service_principal_name(
- 'HTTP', self.api.env.host, realm))
- keytab = paths.IPA_KEYTAB
+ # get anonymous ccache as an armor for FAST to enable OTP auth
armor_path = os.path.join(paths.IPA_CCACHES,
"armor_{}".format(os.getpid()))
- self.debug('Obtaining armor ccache: principal=%s keytab=%s ccache=%s',
- armor_principal, keytab, armor_path)
+ self.debug('Obtaining armor in ccache %s', armor_path)
try:
- kinit_keytab(armor_principal, paths.IPA_KEYTAB, armor_path)
- except gssapi.exceptions.GSSError as e:
- raise CCacheError(message=unicode(e))
+ kinit_armor(armor_path)
+ except RuntimeError as e:
+ self.error("Failed to obtain armor cache")
+ # We try to continue w/o armor, 2FA will be impacted
+ armor_path = None
# Format the user as a kerberos principal
principal = krb5_format_principal_name(user, realm)
@@ -967,11 +965,10 @@ class login_password(Backend, KerberosSession):
kinit_password(principal, password, ccache_name,
armor_ccache_name=armor_path)
- self.debug('Cleanup the armor ccache')
- ipautil.run(
- [paths.KDESTROY, '-A', '-c', armor_path],
- env={'KRB5CCNAME': armor_path},
- raiseonerr=False)
+ if armor_path:
+ self.debug('Cleanup the armor ccache')
+ ipautil.run([paths.KDESTROY, '-A', '-c', armor_path],
+ env={'KRB5CCNAME': armor_path}, raiseonerr=False)
except RuntimeError as e:
if ('kinit: Cannot read password while '
'getting initial credentials') in str(e):