Use ticket forwarding with TurboGears. mod_proxy forwards the principal

name and location of the keytab. In order for this keytab to be usable
 TurboGears and Apache will need to run as the same user. We will also need
 to listen only on localhost in TG.
This commit is contained in:
rcritten@redhat.com committed 2007-09-14 17:19:02 -04:00
1 parent ed6ab17c9c
commit b85668579e
7 files changed
+47 -34

No files matched your search

+6
View File
@@ -47,6 +47,12 @@ class IPAClient:
if self.local:
self.transport.set_principal(princ)
def set_krbccache(self,krbccache):
"""Set the file location of the Kerberos credentials cache to be used
for LDAP authentication"""
if self.local:
self.transport.set_krbccache(krbccache)
# User support
def get_user_by_uid(self,uid,sattrs=None):
"""Get a specific user by uid. If sattrs is set then only those
+9 -8
View File
@@ -2,6 +2,7 @@ import random
from pickle import dumps, loads
from base64 import b64encode, b64decode
import os
import cherrypy
import turbogears
from turbogears import controllers, expose, flash
@@ -77,7 +78,7 @@ class Root(controllers.RootController):
def usercreate(self, **kw):
"""Creates a new user"""
restrict_post()
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
if kw.get('submit') == 'Cancel':
turbogears.flash("Add user cancelled")
raise turbogears.redirect('/userlist')
@@ -115,7 +116,7 @@ class Root(controllers.RootController):
if tg_errors:
turbogears.flash("There was a problem with the form!")
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
user = client.get_user_by_uid(uid, user_fields)
user_dict = user.toDict()
# Edit shouldn't fill in the password field.
@@ -132,7 +133,7 @@ class Root(controllers.RootController):
def userupdate(self, **kw):
"""Updates an existing user"""
restrict_post()
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
if kw.get('submit') == 'Cancel Edit':
turbogears.flash("Edit user cancelled")
raise turbogears.redirect('/usershow', uid=kw.get('uid'))
@@ -181,7 +182,7 @@ class Root(controllers.RootController):
@identity.require(identity.not_anonymous())
def userlist(self, **kw):
"""Retrieve a list of all users and display them in one huge list"""
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
users = None
counter = 0
uid = kw.get('uid')
@@ -204,7 +205,7 @@ class Root(controllers.RootController):
@identity.require(identity.not_anonymous())
def usershow(self, uid):
"""Retrieve a single user for display"""
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
try:
user = client.get_user_by_uid(uid, user_fields)
return dict(user=user.toDict(), fields=forms.user.UserFields())
@@ -242,7 +243,7 @@ class Root(controllers.RootController):
if (len(givenname) == 0) or (len(sn) == 0):
return ""
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
givenname = givenname.lower()
sn = sn.lower()
@@ -328,7 +329,7 @@ class Root(controllers.RootController):
@expose("ipagui.templates.groupindex")
@identity.require(identity.not_anonymous())
def groupindex(self, tg_errors=None):
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
return dict()
@@ -339,5 +340,5 @@ class Root(controllers.RootController):
@expose("ipagui.templates.resindex")
@identity.require(identity.not_anonymous())
def resindex(self, tg_errors=None):
client.set_principal(identity.current.user_name)
client.set_krbccache(os.environ["KRB5CCNAME"])
return dict()
+5 -2
View File
@@ -1,6 +1,7 @@
from turbogears.identity.soprovider import *
from turbogears.identity.visitor import *
import logging
import os
log = logging.getLogger("turbogears.identity")
@@ -97,8 +98,10 @@ class ProxyIdentityProvider(SqlObjectIdentityProvider):
def load_identity(self, visit_key):
try:
# user_name= cherrypy.request.headers['X-FORWARDED-USER']
user_name= "test@FREEIPA.ORG"
user_name= cherrypy.request.headers['X-FORWARDED-USER']
os.environ["KRB5CCNAME"] = cherrypy.request.headers['X-FORWARDED-KEYTAB']
# user_name = "test@FREEIPA.ORG"
# os.environ["KRB5CCNAME"] = "FILE:/tmp/krb5cc_500"
except KeyError:
return None
set_login_attempted( True )
+3 -3
View File
@@ -264,9 +264,9 @@ class IPAdmin(SimpleLDAPObject):
def set_proxydn(self, proxydn):
self.proxydn = proxydn
def set_keytab(self, keytab):
if keytab is not None:
os.environ["KRB5CCNAME"] = keytab
def set_krbccache(self, krbccache):
if krbccache is not None:
os.environ["KRB5CCNAME"] = krbccache
self.sasl_interactive_bind_s("", sasl_auth)
self.proxydn = None
+22 -20
View File
@@ -49,7 +49,7 @@ class IPAConnPool:
def __init__(self):
self.freelist = []
def getConn(self, host, port, bindca, bindcert, bindkey, proxydn=None, keytab=None):
def getConn(self, host, port, bindca, bindcert, bindkey, proxydn=None, krbccache=None):
conn = None
if len(self.freelist) > 0:
for i in range(len(self.freelist)):
@@ -62,12 +62,12 @@ class IPAConnPool:
if proxydn is not None:
conn.set_proxydn(proxydn)
else:
conn.set_keytab(keytab)
conn.set_krbccache(krbccache)
return conn
def releaseConn(self, conn):
# We can't re-use SASL connections. If proxydn is None it means
# we have a keytab set. See ipaldap.set_keytab
# we have a Kerberos credentails cache set. See ipaldap.set_krbccache
if conn.proxydn is None:
conn.unbind_s()
else:
@@ -91,13 +91,13 @@ class IPAServer:
self.basedn = ipa.ipautil.realm_to_suffix(ipa.config.config.get_realm())
self.scope = ldap.SCOPE_SUBTREE
self.princ = None
self.keytab = None
self.krbccache = None
def set_principal(self, princ):
self.princ = princ
def set_keytab(self, keytab):
self.keytab = keytab
def set_krbccache(self, krbccache):
self.krbccache = krbccache
def get_dn_from_principal(self, princ):
"""Given a kerberos principal get the LDAP uid"""
@@ -115,43 +115,45 @@ class IPAServer:
def __setup_connection(self, opts):
"""Set up common things done in the connection.
If there is a keytab then return None as the proxy dn and the keytab
otherwise return the proxy dn and None as the keytab.
If there is a Kerberos credentials cache then return None as the
proxy dn and the ccache otherwise return the proxy dn and None as
the ccache.
We only want one or the other used at one time and we prefer
the keytab. So if there is a keytab, return that and None for
proxy dn to make calling getConn() easier.
the Kerberos credentials cache. So if there is a ccache, return
that and None for proxy dn to make calling getConn() easier.
"""
if opts:
if opts.get('keytab'):
self.set_keytab(opts['keytab'])
if opts.get('krbccache'):
self.set_krbccache(opts['krbccache'])
self.set_principal(None)
else:
self.set_keytab(None)
self.set_krbccache(None)
self.set_principal(opts['remoteuser'])
else:
self.set_keytab(None)
# The caller should have already set the principal
# The caller should have already set the principal or the
# krbccache. If not they'll get an authentication error later.
pass
if self.princ is not None:
return self.get_dn_from_principal(self.princ), None
else:
return None, self.keytab
return None, self.krbccache
def getConnection(self, opts):
"""Wrapper around IPAConnPool.getConn() so we don't have to pass
around self.* every time a connection is needed.
For SASL connections (where we have a keytab) we can't set
For SASL connections (where we have a krbccache) we can't set
the SSL variables for certificates. It confuses the ldap
module.
"""
global _LDAPPool
(proxy_dn, keytab) = self.__setup_connection(opts)
(proxy_dn, krbccache) = self.__setup_connection(opts)
if keytab is not None:
if krbccache is not None:
bindca = None
bindcert = None
bindkey = None
@@ -162,7 +164,7 @@ class IPAServer:
bindkey = self.bindkey
port = self.sslport
return _LDAPPool.getConn(self.host,port,bindca,bindcert,bindkey,proxy_dn,keytab)
return _LDAPPool.getConn(self.host,port,bindca,bindcert,bindkey,proxy_dn,krbccache)
def releaseConnection(self, conn):
global _LDAPPool
+1
View File
@@ -27,6 +27,7 @@ ProxyRequests Off
RewriteCond %{IS_SUBREQ}% false
RewriteRule .* - [E=RU:%{LA-U:REMOTE_USER}]
RequestHeader set X-Forwarded-User %{RU}e
RequestHeader set X-Forwarded-Keytab %{KRB5CCNAME}e
# RequestHeader unset Authorization
</Proxy>
+1 -1
View File
@@ -138,7 +138,7 @@ class ModXMLRPCRequestHandler(object):
opts['remoteuser'] = req.user
if req.subprocess_env.get("KRB5CCNAME") is not None:
opts['keytab'] = req.subprocess_env.get("KRB5CCNAME")
opts['krbccache'] = req.subprocess_env.get("KRB5CCNAME")
# Tack onto the end of the passed-in arguments any options we also
# need