Implement GSSAPI login

Signed-off-by: Patrick Uiterwijk <puiterwijk@redhat.com>
This commit is contained in:
Patrick Uiterwijk 2016-10-26 21:28:59 +00:00 committed by Mike McLean
parent 06f8d24967
commit 480cdfb540
4 changed files with 64 additions and 13 deletions

View file

@ -6968,6 +6968,8 @@ def handle_moshimoshi(options, session, args):
authtype = u.get('authtype', getattr(session, 'authtype', None))
if authtype == koji.AUTHTYPE_NORMAL:
print "Authenticated via password"
elif authtype == koji.AUTHTYPE_GSSAPI:
print "Authenticated via GSSAPI"
elif authtype == koji.AUTHTYPE_KERB:
print "Authenticated via Kerberos principal %s" % u["krb_principal"]
elif authtype == koji.AUTHTYPE_SSL:

View file

@ -29,6 +29,7 @@ Requires: python-krbV >= 1.0.13
Requires: rpm-python
Requires: pyOpenSSL
Requires: python-requests
Requires: python-requests-kerberos
Requires: python-urlgrabber
Requires: python-dateutil
BuildRequires: python

View file

@ -57,6 +57,10 @@ try:
import requests
except ImportError: #pragma: no cover
requests = None
try:
from requests_kerberos import HTTPKerberosAuth
except ImportError: #pragma: no cover
HTTPKerberosAuth = None
import rpm
import shutil
import signal
@ -192,6 +196,7 @@ USER_STATUS = Enum((
AUTHTYPE_NORMAL = 0
AUTHTYPE_KERB = 1
AUTHTYPE_SSL = 2
AUTHTYPE_GSSAPI = 3
#dependency types
DEP_REQUIRE = 0
@ -2017,6 +2022,14 @@ class ClientSession(object):
principal. The principal must be in the "ProxyPrincipals" list on
the server side."""
if principal is None and keytab is None and ccache is None:
try:
# Silently try GSSAPI first
if self.gssapi_login(proxyuser=proxyuser):
return True
except:
pass
if not krbV:
raise exceptions.ImportError(
"Please install python-krbV to use kerberos."
@ -2094,6 +2107,37 @@ class ClientSession(object):
return '%s/%s@%s' % (service, servername, realm)
def gssapi_login(self, proxyuser=None):
if not HTTPKerberosAuth:
raise exceptions.ImportError(
"Please install python-requests-kerberos to use GSSAPI."
)
# force https
uri = urlparse.urlsplit(self.baseurl)
if uri[0] != 'https':
self.baseurl = 'https://%s%s' % (uri[1], uri[2])
# Force a new session
self.new_session()
# 60 second timeout during login
old_opts = self.opts
self.opts = old_opts.copy()
self.opts['timeout'] = 60
self.opts['auth'] = HTTPKerberosAuth()
try:
sinfo = self.callMethod('sslLogin', proxyuser)
finally:
self.opts = old_opts
if not sinfo:
raise AuthError, 'unable to obtain a session'
self.setSession(sinfo)
self.authtype = AUTHTYPE_GSSAPI
return True
def ssl_login(self, cert=None, ca=None, serverca=None, proxyuser=None):
cert = cert or self.opts.get('cert')
serverca = serverca or self.opts.get('serverca')
@ -2222,6 +2266,9 @@ class ClientSession(object):
if cert:
# TODO: we really only need to do this for ssllogin calls
callopts['cert'] = cert
auth = self.opts.get('auth')
if auth:
callopts['auth'] = auth
timeout = self.opts.get('timeout')
if timeout:
callopts['timeout'] = timeout

View file

@ -374,27 +374,28 @@ class Session(object):
if self.logged_in:
raise koji.AuthError, "Already logged in"
if context.environ['wsgi.url_scheme'] != 'https':
raise koji.AuthError, 'cannot call sslLogin() via a non-https connection: %s' % context.environ['wsgi.url_scheme']
if context.environ.get('REMOTE_USER'):
username = context.environ.get('REMOTE_USER')
client_dn = username
authtype = koji.AUTHTYPE_GSSAPI
else:
if context.environ.get('SSL_CLIENT_VERIFY') != 'SUCCESS':
raise koji.AuthError, 'could not verify client: %s' % context.environ.get('SSL_CLIENT_VERIFY')
if context.environ.get('SSL_CLIENT_VERIFY') != 'SUCCESS':
raise koji.AuthError, 'could not verify client: %s' % context.environ.get('SSL_CLIENT_VERIFY')
name_dn_component = context.opts.get('DNUsernameComponent', 'CN')
client_name = context.environ.get('SSL_CLIENT_S_DN_%s' % name_dn_component)
if not client_name:
raise koji.AuthError, 'unable to get user information (%s) from client certificate' % name_dn_component
name_dn_component = context.opts.get('DNUsernameComponent', 'CN')
username = context.environ.get('SSL_CLIENT_S_DN_%s' % name_dn_component)
if not username:
raise koji.AuthError, 'unable to get user information (%s) from client certificate' % name_dn_component
client_dn = context.environ.get('SSL_CLIENT_S_DN')
authtype = koji.AUTHTYPE_SSL
if proxyuser:
client_dn = context.environ.get('SSL_CLIENT_S_DN')
proxy_dns = [dn.strip() for dn in context.opts.get('ProxyDNs', '').split('|')]
if client_dn in proxy_dns:
# the SSL-authenticated user authorized to login other users
username = proxyuser
else:
raise koji.AuthError, '%s is not authorized to login other users' % client_dn
else:
username = client_name
cursor = context.cnx.cursor()
query = """SELECT id FROM users
@ -416,7 +417,7 @@ class Session(object):
if hostip == '127.0.0.1':
hostip = socket.gethostbyname(socket.gethostname())
sinfo = self.createSession(user_id, hostip, koji.AUTHTYPE_SSL)
sinfo = self.createSession(user_id, hostip, authtype)
return sinfo
def makeExclusive(self, force=False):