def krbLogin(self, krb_req, proxyuser=None): """Authenticate the user using the base64-encoded AP_REQ message in krb_req. If proxyuser is not None, log in that user instead of the user associated with the Kerberos principal. The principal must be an authorized "proxy_principal" in the server config.""" if self.logged_in: raise koji.AuthError("Already logged in") if not (context.opts.get('AuthPrincipal') and context.opts.get('AuthKeytab')): raise koji.AuthError('not configured for Kerberos authentication') ctx = krbV.default_context() srvprinc = krbV.Principal(name=context.opts.get('AuthPrincipal'), context=ctx) srvkt = krbV.Keytab(name=context.opts.get('AuthKeytab'), context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE|krbV.KRB5_AUTH_CONTEXT_DO_TIME conninfo = self.getConnInfo() ac.addrs = conninfo # decode and read the authentication request req = base64.decodestring(krb_req) ac, opts, sprinc, ccreds = ctx.rd_req(req, server=srvprinc, keytab=srvkt, auth_context=ac, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = ccreds[2] # Successfully authenticated via Kerberos, now log in if proxyuser: proxyprincs = [princ.strip() for princ in context.opts.get('ProxyPrincipals', '').split(',')] if cprinc.name in proxyprincs: login_principal = proxyuser else: raise koji.AuthError( 'Kerberos principal %s is not authorized to log in other users' % cprinc.name) else: login_principal = cprinc.name user_id = self.getUserIdFromKerberos(login_principal) if not user_id: if context.opts.get('LoginCreatesUser'): user_id = self.createUserFromKerberos(login_principal) else: raise koji.AuthError('Unknown Kerberos principal: %s' % login_principal) self.checkLoginAllowed(user_id) hostip = self.get_remote_ip() sinfo = self.createSession(user_id, hostip, koji.AUTHTYPE_KERB) # encode the reply rep = ctx.mk_rep(auth_context=ac) rep_enc = base64.encodestring(rep) # encrypt and encode the login info sinfo_priv = ac.mk_priv('%(session-id)s %(session-key)s' % sinfo) sinfo_enc = base64.encodestring(sinfo_priv) return (rep_enc, sinfo_enc, conninfo)
def test_krb_login(self): if not krbV: raise SkipTest('krbV module not found') server_princ_name = turbogears.config.get( 'identity.krb_auth_principal', None) if not server_princ_name: # XXX FIXME dead test raise SkipTest('server not configured for krbV') # build krb request ctx = krbV.default_context() try: ccache = ctx.default_ccache() client_princ = ccache.principal() except krbV.Krb5Error: raise SkipTest('client ticket not found, run kinit first') server_princ = krbV.Principal(name=server_princ_name, context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = ctx.default_rcache() ac, req = ctx.mk_req(server=sprinc, client=cprinc, auth_context=ac, ccache=ccache, options=krbV.AP_OPTS_MUTUAL_REQUIRED) encoded_req = base64.encodestring(req) # attempt to log in server = self.get_server() server.auth.login_krbv(encoded_req)
def handle_udp(opts, sock): data, addr = sock.recvfrom(4096) ctx = krbV.default_context() sprinc = krbV.Principal(name=opts.principal, context=ctx) keytab = krbV.Keytab(name=opts.keytab, context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac, options, sprinc, ccreds = ctx.rd_req( data, server=sprinc, keytab=keytab, auth_context=ac, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = ccreds[2] print 'Successfully authenticated via udp: %s' % cprinc.name rep = ctx.mk_rep(auth_context=ac) sock.sendto(rep, addr) msg_enc, addr = sock.recvfrom(4096) print 'Using addresses: %s' % str( (opts.serveraddr[0], opts.serveraddr[1], addr[0], addr[1])) ac.addrs = (opts.serveraddr[0], opts.serveraddr[1], addr[0], addr[1]) msg = ac.rd_priv(msg_enc) print ' Received: %s' % msg resp_enc = ac.mk_priv(msg) sock.sendto(resp_enc, addr)
def udp_client(opts, sock, addr): ctx = krbV.default_context() if opts.ccache: ccache = krbV.CCache(name='FILE:' + opts.ccache, context=ctx) else: ccache = ctx.default_ccache() cprinc = ccache.principal() sprinc = krbV.Principal(name=opts.principal, context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = ctx.default_rcache() ac, req = ctx.mk_req(server=sprinc, client=cprinc, auth_context=ac, ccache=ccache, options=krbV.AP_OPTS_MUTUAL_REQUIRED) sock.sendto(req, addr) rep, saddr = sock.recvfrom(4096) rep_tup = ctx.rd_rep(rep, auth_context=ac) print 'Successfully authenticated via udp to service: %s' % sprinc.name try: addrinfo = socket.getaddrinfo(socket.gethostname(), sock.getsockname()[1], opts.addr_family) localaddr = addrinfo[0][4] except socket.gaierror, e: gai_error(opts, 'local', socket.gethostname(), e)
def login_krbv(request, krb_request, proxy_user=None): """login_krbv(krb_request, proxy_user=None): session_key""" import krbV context = krbV.default_context() server_principal = krbV.Principal(name=settings.KRB_AUTH_PRINCIPAL, context=context) server_keytab = krbV.Keytab(name=settings.KRB_AUTH_KEYTAB, context=context) auth_context = krbV.AuthContext(context=context) auth_context.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME auth_context.addrs = (socket.gethostbyname(request.META["HTTP_HOST"]), 0, request.META["REMOTE_ADDR"], 0) # decode and read the authentication request decoded_request = base64.decodestring(krb_request) auth_context, opts, server_principal, cache_credentials = context.rd_req(decoded_request, server=server_principal, keytab=server_keytab, auth_context=auth_context, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = cache_credentials[2] # remove @REALM username = cprinc.name.split("@")[0] backend = Krb5RemoteUserBackend() user = backend.authenticate(username) if user is None: raise PermissionDenied() user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__) django.contrib.auth.login(request, user) return request.session.session_key
def login_krbV(self, krb_request, proxy_user=None): """ Authenticates the current session using Kerberos. The caller may act as a proxy on behalf of another user by passing the *proxy_user* argument. This requires that the caller has 'proxy_auth' permission. :param krb_request: KRB_AP_REQ message containing client credentials, as produced by :c:func:`krb5_mk_req` :type krb_request: base64-encoded string :param proxy_user: username on whose behalf the caller is proxying :type proxy_user: string or None This method is also available under the alias :meth:`auth.login_krbv`, for compatibility with `Kobo`_. """ import krbV import base64 context = krbV.default_context() server_principal = krbV.Principal(name=KRB_AUTH_PRINCIPAL, context=context) server_keytab = krbV.Keytab(name=KRB_AUTH_KEYTAB, context=context) auth_context = krbV.AuthContext(context=context) auth_context.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME auth_context.addrs = (socket.gethostbyname( cherrypy.request.remote_host), 0, cherrypy.request.remote_addr, 0) # decode and read the authentication request decoded_request = base64.decodestring(krb_request) auth_context, opts, server_principal, cache_credentials = context.rd_req( decoded_request, server=server_principal, keytab=server_keytab, auth_context=auth_context, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = cache_credentials[2] # remove @REALM username = cprinc.name.split("@")[0] user = User.by_user_name(username) if user is None: raise LoginException(_(u'Invalid username')) if not user.can_log_in(): raise LoginException(_(u'Invalid username')) if proxy_user: if not user.has_permission(u'proxy_auth'): raise LoginException( _(u'%s does not have proxy_auth permission') % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise LoginException( _(u'Proxy user %s does not exist') % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return username
def _login_krbv(self): """Login using kerberos credentials (uses python-krbV).""" # read default values from settings principal = self._conf.get("KRB_PRINCIPAL") keytab = self._conf.get("KRB_KEYTAB") service = self._conf.get("KRB_SERVICE") realm = self._conf.get("KRB_REALM") ccache = self._conf.get("KRB_CCACHE") proxyuser = self._conf.get("KRB_PROXYUSER") import krbV ctx = krbV.default_context() if ccache is not None: ccache = krbV.CCache(name='FILE:' + ccache, context=ctx) else: ccache = ctx.default_ccache() if principal is not None: if keytab is not None: cprinc = krbV.Principal(name=principal, context=ctx) keytab = krbV.Keytab(name=keytab, context=ctx) ccache.init(cprinc) ccache.init_creds_keytab(principal=cprinc, keytab=keytab) else: raise ImproperlyConfigured( "Cannot specify a principal without a keytab") else: # connect using existing credentials cprinc = ccache.principal() sprinc = krbV.Principal(name=self.get_server_principal(service=service, realm=realm), context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = ctx.default_rcache() # create and encode the authentication request try: ac, req = ctx.mk_req(server=sprinc, client=cprinc, auth_context=ac, ccache=ccache, options=krbV.AP_OPTS_MUTUAL_REQUIRED) except krbV.Krb5Error as ex: if getattr(ex, "err_code", None) == -1765328377: ex.message += ". Make sure you correctly set KRB_REALM (current value: %s)." % realm ex.args = (ex.err_code, ex.message) raise ex encode_func = base64.encodebytes if hasattr( base64, "encodebytes") else base64.encodestring req_enc = encode_func(req) self._hub.auth.login_krbv(req_enc)
def login_krbv(): """ Authenticates the current session using Kerberos. The caller may act as a proxy on behalf of another user by passing the *proxy_user* key. This requires that the caller has 'proxy_auth' permission. The request body must be a JSON object containing krb_request. Proxy_user is optional. :jsonparam base64-encoded-string krb_request: KRB_AP_REQ message containing client credentials, as produced by :c:func:`krb5_mk_req` :jsonparam string proxy_user: Username on whose behalf the caller is proxying """ import krbV import base64 payload = read_json_request(request) krb_request = payload.get('krb_request') proxy_user = payload.get('proxy_user') context = krbV.default_context() server_principal = krbV.Principal(name=KRB_AUTH_PRINCIPAL, context=context) server_keytab = krbV.Keytab(name=KRB_AUTH_KEYTAB, context=context) auth_context = krbV.AuthContext(context=context) auth_context.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME auth_context.addrs = (socket.gethostbyaddr(request.remote_addr), 0, request.remote_addr, 0) # decode and read the authentication request decoded_request = base64.decodestring(krb_request) auth_context, opts, server_principal, cache_credentials = context.rd_req( decoded_request, server=server_principal, keytab=server_keytab, auth_context=auth_context, options=krbV.AP_OPTS_MUTUAL_REQUIRED) cprinc = cache_credentials[2] # remove @REALM username = cprinc.name.split("@")[0] user = User.by_user_name(username) if user is None: raise Unauthorised401(u'Invalid username') if not user.can_log_in(): raise Unauthorised401(u'Invalid username') if proxy_user: if not user.has_permission(u'proxy_auth'): raise Unauthorised401(u'%s does not have proxy_auth permission' % user.user_name) proxied_user = User.by_user_name(proxy_user) if proxied_user is None: raise Unauthorised401(u'Proxy user %s does not exist' % proxy_user) identity.set_authentication(proxied_user, proxied_by=user) else: identity.set_authentication(user) return jsonify({'username': user.user_name})
def get_encoded_request(self, full_principal): sprinc = krbV.Principal(name=full_principal, context=self.context) ac = krbV.AuthContext(context=self.context) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = self.context.default_rcache() # create and encode the authentication request try: req = self._create_request(sprinc, ac) except krbV.Krb5Error, e: if 'Ticket expired' in str(e): self.reinit() req = self._create_request(sprinc, ac) else: raise
def _login_krbv(self): """Login using kerberos credentials (uses python-krbV).""" def get_server_principal(service=None, realm=None): """Convert hub url to kerberos principal.""" hostname = urlparse.urlparse(self._hub_url)[1] # remove port from hostname hostname = hostname.split(":")[0] if realm is None: # guess realm: last two parts from hostname realm = ".".join(hostname.split(".")[-2:]).upper() if service is None: service = "HTTP" return '%s/%s@%s' % (service, hostname, realm) # read default values from settings principal = self._conf.get("KRB_PRINCIPAL") keytab = self._conf.get("KRB_KEYTAB") service = self._conf.get("KRB_SERVICE") realm = self._conf.get("KRB_REALM") ccache = self._conf.get("KRB_CCACHE") proxyuser = self._conf.get("PROXY_USER") import krbV ctx = krbV.default_context() if ccache is not None: ccache = krbV.CCache(name='FILE:' + ccache, context=ctx) elif keytab is not None: # If we will be init'ing the ccache using a keytab, we need to # always avoid using the default shared ccache, as a workaround for # a race condition in krb5_cc_initialize() between unlink() and open() # (see RHBZ#1313580). ccache_tmpfile = tempfile.NamedTemporaryFile(prefix='krb5cc_bkr_') ccache = krbV.CCache(name='FILE:' + ccache_tmpfile.name, context=ctx) else: ccache = ctx.default_ccache() if principal is not None: if keytab is not None: cprinc = krbV.Principal(name=principal, context=ctx) keytab = krbV.Keytab(name=keytab, context=ctx) ccache.init(cprinc) ccache.init_creds_keytab(principal=cprinc, keytab=keytab) else: raise ImproperlyConfigured( "Cannot specify a principal without a keytab") else: # connect using existing credentials cprinc = ccache.principal() sprinc = krbV.Principal(name=get_server_principal(service=service, realm=realm), context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = ctx.default_rcache() # create and encode the authentication request try: ac, req = ctx.mk_req(server=sprinc, client=cprinc, auth_context=ac, ccache=ccache, options=krbV.AP_OPTS_MUTUAL_REQUIRED) except krbV.Krb5Error, ex: if getattr(ex, "err_code", None) == -1765328377: ex.message += ". Make sure you correctly set KRB_REALM (current value: %s)." % realm ex.args = (ex.err_code, ex.message) raise ex
def finish_state(self): if self.state == self.STATE_SETUP: self.state = self.STATE_READING elif self.state == self.STATE_READING: authmgr = self.coord.app.auth remprinc = self.read_vals['remprinc'] creds = (authmgr.primary_principal, krbV.Principal(remprinc, context=authmgr.context), (0, None), (0, 0, 0, 0), None, None, None, None, self.read_vals['reqdata'], None) ac = None req = None need_retry = 10 while need_retry: need_retry -= 1 try: ocreds = authmgr.ccache.get_credentials( creds, options=krbV.KRB5_GC_USER_USER) ac = krbV.AuthContext(context=authmgr.context) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE opts = krbV.AP_OPTS_USE_SESSION_KEY | krbV.AP_OPTS_MUTUAL_REQUIRED req = authmgr.context.mk_req(options=opts, creds=ocreds, auth_context=ac, ccache=authmgr.ccache) need_retry = 0 except krbV.Krb5Error, e: if not need_retry: raise if e.err_code != krbV.KRB5KRB_AP_ERR_TKT_EXPIRED: raise authmgr.reinit() ourid = None if self.idmap.has_key(self.read_vals['remid']): ourid = self.idmap[self.read_vals['remid']] assert type(ourid) in (tuple, list) self.cnx = ourid[1] self.cnx.cnxid = ourid[0] ourid = ourid[0] else: for I in self.coord.all_cnxs: if I.cnxaddr and socket.gethostbyname( I.cnxaddr[0]) == socket.gethostbyname( self.addr[0] ) and I.name == self.read_vals['remname']: if I.cnx_state == I.CNX_CONNECTED: # If we have an outgoing connection with the same info, we just drop this incoming one on the floor. self.coord.log( 'Dropping incoming connection from %s because it matches outgoing connection %#x', self.addr, id(I), level='debug', local=1) return self.fail() else: I.set_cnx_state(I.CNX_TERMINATED, do_lock=1) ourid = apiary.util.get_rand_str(prand=1) self.cnx = Connection(self.coord, cnxid=ourid) assert self.cnx.connector != self if self.cnx.connector: self.cnx.connector.fail() self.cnx.connector = self self.cnx.set_cnx_state(self.cnx.CNX_CONNECTING, do_lock=1) self.write_vals = { 'localname': self.cnx.coord.app.localname, 'cnxid': ourid, 'localprinc': creds[0].name, 'reqdata': req[1] } ac.genaddrs(self.cnxsock, flags=krbV.KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | krbV.KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR) self.read_vals['ac'] = ac self.read_vals['user'] = remprinc assert type(remprinc) == str self.state = self.STATE_WRITING
'cnxid': self.cnx.cnxid, 'localprinc': princ.name, 'reqdata': ocreds[7], 'useruserkey': ocreds[2] } self.state = self.STATE_WRITING elif self.state == self.STATE_WRITING: self.state = self.STATE_READING elif self.state == self.STATE_READING: ac = None res = None need_retry = 1 authmgr = self.cnx.coord.app.auth while need_retry: try: ac = krbV.AuthContext(context=authmgr.context) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE ac.useruserkey = self.write_vals['useruserkey'] res = authmgr.context.rd_req( self.read_vals['reqdata'], auth_context=ac, server=authmgr.primary_principal) need_retry = 0 except krbV.Krb5Error, e: if e.err_code != krbV.KRB5KRB_AP_ERR_TKT_EXPIRED: return self.fail("Kerberos error %s/%s" % (e.err_code, e.message)) authmgr.reinit() ac.genaddrs(self.cnxsock, flags=krbV.KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | krbV.KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
def _login_krbv(self): """Login using kerberos credentials (uses python-krbV).""" def get_server_principal(service=None, realm=None): """Convert hub url to kerberos principal.""" hostname = urlparse.urlparse(self._hub_url)[1] # remove port from hostname hostname = hostname.split(":")[0] if realm is None: # guess realm: last two parts from hostname realm = ".".join(hostname.split(".")[-2:]).upper() if service is None: service = "HTTP" return '%s/%s@%s' % (service, hostname, realm) # read default values from settings principal = self._conf.get("KRB_PRINCIPAL") keytab = self._conf.get("KRB_KEYTAB") service = self._conf.get("KRB_SERVICE") realm = self._conf.get("KRB_REALM") ccache = self._conf.get("KRB_CCACHE") proxyuser = self._conf.get("KRB_PROXYUSER") import krbV ctx = krbV.default_context() if ccache is not None: ccache = krbV.CCache(name='FILE:' + ccache, context=ctx) else: ccache = ctx.default_ccache() if principal is not None: if keytab is not None: cprinc = krbV.Principal(name=principal, context=ctx) keytab = krbV.Keytab(name=keytab, context=ctx) ccache.init(cprinc) ccache.init_creds_keytab(principal=cprinc, keytab=keytab) else: raise ImproperlyConfigured( "Cannot specify a principal without a keytab") else: # connect using existing credentials cprinc = ccache.principal() sprinc = krbV.Principal(name=get_server_principal(service=service, realm=realm), context=ctx) ac = krbV.AuthContext(context=ctx) ac.flags = krbV.KRB5_AUTH_CONTEXT_DO_SEQUENCE | krbV.KRB5_AUTH_CONTEXT_DO_TIME ac.rcache = ctx.default_rcache() # create and encode the authentication request try: ac, req = ctx.mk_req(server=sprinc, client=cprinc, auth_context=ac, ccache=ccache, options=krbV.AP_OPTS_MUTUAL_REQUIRED) except krbV.Krb5Error as ex: if getattr(ex, "err_code", None) == -1765328377: ex.message += ". Make sure you correctly set KRB_REALM (current value: %s)." % realm ex.args = (ex.err_code, ex.message) raise ex req_enc = base64.encodestring(req) self._hub.auth.login_krbv(req_enc)