def auth_negotiate(self, auth_header, callback): """ Perform Negotiate (GSSAPI/SSO) authentication via Kerberos. """ auth_str = auth_header.split()[1] # Initialize Kerberos Context try: result, context = kerberos.authGSSServerInit( self.settings['sso_service']) if result != 1: raise tornado.web.HTTPError(500, _("Kerberos Init failed")) result = kerberos.authGSSServerStep(context, auth_str) if result == 1: gssstring = kerberos.authGSSServerResponse(context) else: # Fall back to Basic auth self.auth_basic(auth_header, callback) # NOTE: The user we get from Negotiate is a full UPN (user@REALM) user = kerberos.authGSSServerUserName(context) except kerberos.GSSError as e: logging.error(_("Kerberos Error: %s" % e)) raise tornado.web.HTTPError(500, _("Kerberos Init failed")) finally: kerberos.authGSSServerClean(context) self.set_header('WWW-Authenticate', "Negotiate %s" % gssstring) callback(user)
def authorize(self, req, app, app_args, app_kwargs): """Perform a Kerberos authentication handshake with the KDC.""" http_auth = req.environ.get(self.AUTH_HEADER) if not http_auth: log.info('kerberos: rejecting non-authed request from %s', req.environ.get('REMOTE_ADDR')) return self.auth_fail() log.debug('kerberos: processing auth: %s', http_auth) auth_type, auth_key = self.parse_auth_header(http_auth) if auth_type == 'Negotiate': # Initialize a kerberos context. try: result, context = kerberos.authGSSServerInit(self._service) log.debug('kerberos: authGSSServerInit(%s) -> %s, %s', self._service, result, context) except kerberos.GSSError as e: log.warning('kerberos: GSSError during init: %s', e) result, context = 0, None if not self.check_result(result): log.warning( 'kerberos: bad result from authGSSServerInit(%s): %s', self._service, result) return self.auth_error() # Process the next challenge step and retrieve the response. gss_key = None try: result = kerberos.authGSSServerStep(context, auth_key) log.debug('kerberos: authGSSServerStep(%s, %s) -> %s', context, auth_key, result) gss_key = kerberos.authGSSServerResponse(context) log.debug('kerberos: authGSSServerResponse(%s) -> %s', context, gss_key) except kerberos.GSSError as e: log.warning('kerberos: GSSError(%s)', e) result = 0 if not self.check_result(result): return self.auth_fail(gss_key) # Retrieve the user id and add it to the request environment. username = kerberos.authGSSServerUserName(context) req.environ['REMOTE_USER'] = username log.info('kerberos: authenticated user %s from %s', username, req.environ.get('REMOTE_ADDR')) # Pass on the GSS response in the Bottle response. response.set_header('WWW-Authenticate', 'Negotiate ' + str(gss_key)) # Clean up. kerberos.authGSSServerClean(context) return app(*app_args, **app_kwargs) else: return self.auth_fail()
def get_kerberos_userid(request): if not request.authorization or request.authorization[0] != 'Negotiate': if 'challenge' in request.params: raise HTTPUnauthorized(headers={'WWW-Authenticate': 'Negotiate'}) return None ticket = request.authorization[1] log.debug("Kerberos ticket received: %s" % ticket) service = 'HTTP@%s' % request.host.split(':')[0] result, context = kerberos.authGSSServerInit(service) if result != 1: log.error("Could not initialize Kerberos GSS service.") return None try: try: if not kerberos.authGSSServerStep(context, ticket) == 1: return None except kerberos.GSSError, e: log.warn("%s: GSSError %s\nTicket: %s" % (request.remote_addr, e, ticket)) return None principal = kerberos.authGSSServerUserName(context)
def _authenticate(self, client_token): ''' Validate the client token Return the authenticated users principal and a token suitable to provide mutual authentication to the client. ''' state = None server_token = None user = None try: rc, state = kerberos.authGSSServerInit(self.service) if rc == kerberos.AUTH_GSS_COMPLETE: rc = kerberos.authGSSServerStep(state, client_token) if rc == kerberos.AUTH_GSS_COMPLETE: server_token = kerberos.authGSSServerResponse(state) user = kerberos.authGSSServerUserName(state) elif rc == kerberos.AUTH_GSS_CONTINUE: server_token = kerberos.authGSSServerResponse(state) except kerberos.GSSError as exc: LOG.error("Unhandled GSSError: %s", exc) finally: if state: kerberos.authGSSServerClean(state) return server_token, user
def authenticate(self, handler, data): ''' Performs GSSAPI Negotiate Authentication @param token: GSSAPI Authentication Token @type token: str @returns gssapi return code or None on failure @rtype: int or None ''' state = None try: rc, state = kerberos.authGSSServerInit(self.service_name) self.log.info("kerberos.authGSSServerInit") if rc != kerberos.AUTH_GSS_COMPLETE: return None rc = kerberos.authGSSServerStep(state, data) self.log.info("kerberos.authGSSServerStep") if rc == kerberos.AUTH_GSS_COMPLETE: user = kerberos.authGSSServerUserName(state) self.log.info("Extracted User = "******"kerberos.AUTH_GSS_COMPLETE:" + user elif rc == kerberos.AUTH_GSS_CONTINUE: return "kerberos.AUTH_GSS_CONTINUE" else: self.log.info("return None") return None except kerberos.GSSError as err: self.log.info("kerberos.GSSError: {0}".format(err)) return None finally: if state: kerberos.authGSSServerClean(state)
def _authenticate(self, client_token): ''' Validate the client token Return the authenticated users principal and a token suitable to provide mutual authentication to the client. ''' state = None server_token = None user = None try: rc, state = kerberos.authGSSServerInit(self.service) if rc == kerberos.AUTH_GSS_COMPLETE: rc = kerberos.authGSSServerStep(state, client_token) if rc == kerberos.AUTH_GSS_COMPLETE: server_token = kerberos.authGSSServerResponse(state) user = kerberos.authGSSServerUserName(state) elif rc == kerberos.AUTH_GSS_CONTINUE: server_token = kerberos.authGSSServerResponse(state) except kerberos.GSSError: pass finally: if state: kerberos.authGSSServerClean(state) return server_token, user
def wrapped(resource, req, resp, *args, **kwargs): authorization = req.get_header("Authorization") if not authorization: resp.append_header("WWW-Authenticate", "Negotiate") raise falcon.HTTPUnauthorized("Unauthorized", "No Kerberos ticket offered?") token = ''.join(authorization.split()[1:]) rc, context = kerberos.authGSSServerInit("HTTP@" + FQDN) if rc != kerberos.AUTH_GSS_COMPLETE: raise falcon.HTTPForbidden("Forbidden", "Kerberos ticket expired?") rc = kerberos.authGSSServerStep(context, token) kerberos_user = kerberos.authGSSServerUserName(context).split("@") # References lost beyond this point! Results in # ValueError: PyCapsule_SetPointer called with null pointer kerberos.authGSSServerClean(context) if rc == kerberos.AUTH_GSS_COMPLETE: kwargs["user"] = kerberos_user return func(resource, req, resp, *args, **kwargs) elif rc == kerberos.AUTH_GSS_CONTINUE: raise falcon.HTTPUnauthorized("Unauthorized", "Tried GSSAPI") else: raise falcon.HTTPForbidden("Forbidden", "Tried GSSAPI")
def _gssapi_authenticate(token): """ Performs GSSAPI Negotiate Authentication On success also stashes the server response token for mutual authentication at the top of request context with the name kerberos_token, along with the authenticated user principal with the name kerberos_user. @param token: GSSAPI Authentication Token @type token: str @returns gssapi return code or None on failure @rtype: int or None """ state = None # Should be a request local object ctx = request.ctx try: rc, state = kerberos.authGSSServerInit(_SERVICE_NAME) if rc != kerberos.AUTH_GSS_COMPLETE: return None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: ctx.kerberos_token = kerberos.authGSSServerResponse(state) ctx.kerberos_user = kerberos.authGSSServerUserName(state) return rc elif rc == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE else: return None except kerberos.GSSError: return None finally: if state: kerberos.authGSSServerClean(state)
def _doNegotiateAuth(self): _ignore_result, context = kerberos.authGSSServerInit("") try: self._getKerberosDetails() kerberos.authGSSServerStep(context, self.authToken) targetName = kerberos.authGSSServerTargetName(context) if targetName.lower() != self._kerberosPrincipal.lower(): raise Exception( "Target name did not match local principal - %s vs %s" % (targetName, self._kerberosPrincipal)) response = kerberos.authGSSServerResponse(context) principal = kerberos.authGSSServerUserName(context) (user, realm) = principal.split("@", 1) if realm.lower() != self._kerberosRealm.lower(): raise Exception("Mismatched realms - %s vs %s" % (realm, self._kerberosRealm)) self.user = user self.page.responseHeaders.append( ("WWW-Authenticate", "Negotiate %s" % response)) print "Did negotiate auth for %s" % self.user except: print "Failed negotiate auth" self.page.offerNegotiate = False raise finally: kerberos.authGSSServerClean(context)
def login_krb5(self, session, token): ctx = None if AuthenticationManager.has_krb5(): import kerberos try: server_principal = "HTTP@" + self.function.server.instance_address (res, ctx) = kerberos.authGSSServerInit(server_principal) res = kerberos.authGSSServerStep(ctx, token) if res != kerberos.AUTH_GSS_COMPLETE: raise exterror.ExtAccessDeniedError() authprinc = kerberos.authGSSServerUserName(ctx) if '@' in authprinc: priminst, realm = authprinc.split('@') if "/" in priminst: primary, instance = priminst.split("/") else: primary, instance = priminst, "" else: primary, instance, realm = authprinc, "", "" session.set("authuser", primary) session.set("authinst", instance) session.set("authrealm", realm) finally: if ctx: kerberos.authGSSServerClean(ctx) else: raise exterror.ExtAuthenticationFailedError()
def get_kerberos_userid(request): if not request.authorization or request.authorization[0] != 'Negotiate': if 'challenge' in request.params: raise HTTPUnauthorized(headers={'WWW-Authenticate': 'Negotiate'}) return None ticket = request.authorization[1] log.debug("Kerberos ticket received: %s" % ticket) service = 'HTTP@%s' % request.host.split(':')[0] result, context = kerberos.authGSSServerInit(service) if result != 1: log.error("Could not initialize Kerberos GSS service.") return None try: try: if not kerberos.authGSSServerStep(context,ticket) == 1: return None except kerberos.GSSError, e: log.warn("%s: GSSError %s\nTicket: %s" % ( request.remote_addr, e, ticket)) return None principal = kerberos.authGSSServerUserName(context)
def auth_negotiate(self, auth_header, callback): """ Perform Negotiate (GSSAPI/SSO) authentication via Kerberos. """ auth_str = auth_header.split()[1] # Initialize Kerberos Context context = None try: result, context = kerberos.authGSSServerInit( self.settings['sso_service']) if result != 1: raise tornado.web.HTTPError(500, _("Kerberos Init failed")) result = kerberos.authGSSServerStep(context, auth_str) if result == 1: gssstring = kerberos.authGSSServerResponse(context) else: # Fall back to Basic auth self.auth_basic(auth_header, callback) # NOTE: The user we get from Negotiate is a full UPN (user@REALM) user = kerberos.authGSSServerUserName(context) except kerberos.GSSError as e: logging.error(_("Kerberos Error: %s" % e)) raise tornado.web.HTTPError(500, _("Kerberos Init failed")) finally: if context: kerberos.authGSSServerClean(context) self.set_header('WWW-Authenticate', "Negotiate %s" % gssstring) callback(user)
def authenticate(self, request, context): spnego_token = self._get_spnego_token(context) gcssapi_context = None try: # Initialize GSSAPI context result, gcssapi_context = kerberos.authGSSServerInit( f'{settings.BROKER_SERVICE_NAME}@{settings.BROKER_SERVICE_HOSTNAME}' ) if result != kerberos.AUTH_GSS_COMPLETE: # The GSSAPI context initialization failed abort(grpc.StatusCode.PERMISSION_DENIED) # Process the client-supplied SPNEGO token result = kerberos.authGSSServerStep(gcssapi_context, spnego_token) if result == kerberos.AUTH_GSS_COMPLETE: # Authentication succeded. Return the authenticated principal's username. principal = kerberos.authGSSServerUserName(gcssapi_context) return principal else: # Authentication failed abort(grpc.StatusCode.PERMISSION_DENIED) except kerberos.GSSError: abort(grpc.StatusCode.PERMISSION_DENIED) finally: # Destroy the GSSAPI context if gcssapi_context: kerberos.authGSSServerClean(gcssapi_context)
def _gssapi_authenticate(token): ''' Performs GSSAPI Negotiate Authentication On success also stashes the server response token for mutual authentication at the top of request context with the name kerberos_token, along with the authenticated user principal with the name kerberos_user. @param token: GSSAPI Authentication Token @type token: str @returns gssapi return code or None on failure @rtype: int or None ''' state = None # Should be a request local object ctx = request.ctx try: rc, state = kerberos.authGSSServerInit(_SERVICE_NAME) if rc != kerberos.AUTH_GSS_COMPLETE: return None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: ctx.kerberos_token = kerberos.authGSSServerResponse(state) ctx.kerberos_user = kerberos.authGSSServerUserName(state) return rc elif rc == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE else: return None except kerberos.GSSError: return None finally: if state: kerberos.authGSSServerClean(state)
def check_ticket(self, ticket): init_context_res = chech_ticket_res = -1 principal = realm = orig_service = target_name = service = '' try: principal = kerberos.getServerPrincipalDetails( self._service_type, self._hostname) orig_service, realm = self._split_principal(principal) init_context_res, context = kerberos.authGSSServerInit('') chech_ticket_res = kerberos.authGSSServerStep(context, ticket) target_name = kerberos.authGSSServerTargetName(context) service, _ = self._split_principal(target_name) response = kerberos.authGSSServerResponse(context) principal = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) except kerberos.GSSError: if init_context_res != 1: ERROR("Error init kerberos context") elif chech_ticket_res == -1: ERROR("Ticket is not correct:" + ticket) elif service.lower() != orig_service.lower(): ERROR('Bad credentials: wrong target name ' + target_name) return '', '', '' except kerberos.KrbError: ERROR("Internal kerberos error") return '', '', '' # del kerberos username, realm = principal.split('@') return response, username, realm
def _kerberos_auth(token): """ Performs GSSAPI Negotiate Authentication Returns the retrun code and state so that token and user principle can be retrieved. @param token: GSSAPI Authentication Token @returns gssapi return and state @rtype: int or None, PyCObject """ state = None rc = None context = stack.top try: rc, state = kerberos.authGSSServerInit(_SERVICE_NAME) if rc != kerberos.AUTH_GSS_COMPLETE: return None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: context.kerberos_token = kerberos.authGSSServerResponse(state) context.kerberos_user = kerberos.authGSSServerUserName(state) return rc elif rc == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE else: return None except kerberos.GSSError: return None finally: if state: kerberos.authGSSServerClean(state)
def get_current_user_kerberos(self): """Authenticate the current user using kerberos. Returns ------- user : str The current user name. """ import kerberos auth_header = self.request.headers.get("Authorization") if not auth_header: return self._raise_auth_required() auth_type, auth_key = auth_header.split(" ", 1) if auth_type != "Negotiate": return self._raise_auth_required() if _SERVICE_NAME is None: raise RuntimeError( "Kerberos not initialized, must call `init_kerberos` before " "serving requests") gss_context = None try: # Initialize kerberos context rc, gss_context = kerberos.authGSSServerInit(_SERVICE_NAME) # NOTE: Per the pykerberos documentation, the return code should be # checked after each step. However, after reading the pykerberos # code no method used here will ever return anything but # AUTH_GSS_COMPLETE (all other cases will raise an exception). We # keep these checks in just in case pykerberos changes its behavior # to match its docs, but they likely never will trigger. if rc != kerberos.AUTH_GSS_COMPLETE: return self._raise_auth_error( "GSS server init failed, return code = %r" % rc) # Challenge step rc = kerberos.authGSSServerStep(gss_context, auth_key) if rc != kerberos.AUTH_GSS_COMPLETE: return self._raise_auth_error( "GSS server step failed, return code = %r" % rc) gss_key = kerberos.authGSSServerResponse(gss_context) # Retrieve user name fulluser = kerberos.authGSSServerUserName(gss_context) user = fulluser.split("@", 1)[0] # Complete the protocol by responding with the Negotiate header self.set_header("WWW-Authenticate", "Negotiate %s" % gss_key) except kerberos.GSSError as err: return self._raise_auth_error(err) finally: if gss_context is not None: kerberos.authGSSServerClean(gss_context) return user
def authenticateCredentials(self, credentials): """ See IAuthenticationPlugin. o We expect the credentials to be those returned by ILoginPasswordExtractionPlugin. """ # We only authenticate when our challenge mechanism extracted # the ticket if credentials.get('plugin') != self.getId(): return None request = self.REQUEST response = request.RESPONSE remote_host = request.getClientAddr() # We are actually already authenticated... maybe we are in a subrequest if request.get('AUTHENTICATED_USER', None) is not None: username = request.AUTHENTICATED_USER.getName() return username, username ticket = credentials['ticket'] if WINDOWS: sa = sspi.ServerAuth('Negotiate') sa.reset() data = ticket.decode('base64') err, sec_buffer = sa.authorize(data) if err == 0: username = sa.ctxt.QueryContextAttributes( sspicon.SECPKG_ATTR_NAMES) else: raise Forbidden else: service = self.service if not service: service = "HTTP/" + urlparse.urlsplit( request.SERVER_URL).netloc result, context = kerberos.authGSSServerInit(service) if result != 1: raise ValueError, "Kerberos authetication error" gssstring = '' try: r = kerberos.authGSSServerStep(context, ticket) if r == 1: gssstring = kerberos.authGSSServerResponse(context) else: raise Forbidden except GSSError, e: LOG('SPNEGO plugin', ERROR, "%s: GSSError %s" % (remote_host, e)) raise Forbidden username = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context)
def decode(self, base64data, request): # Init GSSAPI first - we won't specify the service now as we need to accept a target # name that is case-insenstive as some clients will use "http" instead of "HTTP" try: _ignore_result, context = kerberos.authGSSServerInit(""); except kerberos.GSSError, ex: self.log_error("authGSSServerInit: %s(%s)" % (ex[0][0], ex[1][0],)) raise error.LoginFailed('Authentication System Failure: %s(%s)' % (ex[0][0], ex[1][0],))
def authenticateCredentials( self, credentials ): """ See IAuthenticationPlugin. o We expect the credentials to be those returned by ILoginPasswordExtractionPlugin. """ # We only authenticate when our challenge mechanism extracted # the ticket if credentials.get('plugin') != self.getId(): return None request = self.REQUEST response = request.RESPONSE remote_host = request.getClientAddr() # We are actually already authenticated... maybe we are in a subrequest if request.get('AUTHENTICATED_USER', None) is not None: username = request.AUTHENTICATED_USER.getName() return username, username ticket = credentials['ticket'] if WINDOWS: sa = sspi.ServerAuth('Negotiate') sa.reset() data = ticket.decode('base64') err, sec_buffer = sa.authorize(data) if err == 0: username = sa.ctxt.QueryContextAttributes( sspicon.SECPKG_ATTR_NAMES) else: raise Forbidden else: service = self.service if not service: service = "HTTP/" + urlparse.urlsplit(request.SERVER_URL).netloc result, context = kerberos.authGSSServerInit(service) if result != 1: raise ValueError, "Kerberos authetication error" gssstring='' try: r=kerberos.authGSSServerStep(context,ticket) if r == 1: gssstring=kerberos.authGSSServerResponse(context) else: raise Forbidden except GSSError, e: LOG('SPNEGO plugin', ERROR, "%s: GSSError %s" % (remote_host, e)) raise Forbidden username=kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context)
def decode(self, base64data, request): # Init GSSAPI first - we won't specify the service now as we need to accept a target # name that is case-insenstive as some clients will use "http" instead of "HTTP" try: _ignore_result, context = kerberos.authGSSServerInit("") except kerberos.GSSError, ex: self.log.error("authGSSServerInit: {ex0}({ex1})", ex0=ex[0][0], ex1=ex[1][0]) raise error.LoginFailed('Authentication System Failure: %s(%s)' % (ex[0][0], ex[1][0],))
def __enter__(self): try: res, self.context = kerberos.authGSSServerInit(self.serviceType) except kerberos.KrbError as e: msg = repr(e) log.msg(msg) raise LoginFailed(msg) if res < 0: raise LoginFailed() return self
def authorize(self, req, app, app_args, app_kwargs): """Perform a Kerberos authentication handshake with the KDC.""" http_auth = req.environ.get(self.AUTH_HEADER) if not http_auth: log.info('kerberos: rejecting non-authed request from %s', req.environ.get('REMOTE_ADDR')) return self.auth_fail() log.debug('kerberos: processing auth: %s', http_auth) auth_type, auth_key = self.parse_auth_header(http_auth) if auth_type == 'Negotiate': # Initialize a kerberos context. try: result, context = kerberos.authGSSServerInit(self._service) log.debug('kerberos: authGSSServerInit(%s) -> %s, %s', self._service, result, context) except kerberos.GSSError as e: log.warning('kerberos: GSSError during init: %s', e) result, context = 0, None if not self.check_result(result): log.warning('kerberos: bad result from authGSSServerInit(%s): %s', self._service, result) return self.auth_error() # Process the next challenge step and retrieve the response. gss_key = None try: result = kerberos.authGSSServerStep(context, auth_key) log.debug('kerberos: authGSSServerStep(%s, %s) -> %s', context, auth_key, result) gss_key = kerberos.authGSSServerResponse(context) log.debug('kerberos: authGSSServerResponse(%s) -> %s', context, gss_key) except kerberos.GSSError as e: log.warning('kerberos: GSSError(%s)', e) result = 0 if not self.check_result(result): return self.auth_fail(gss_key) # Retrieve the user id and add it to the request environment. username = kerberos.authGSSServerUserName(context) req.environ['REMOTE_USER'] = username log.info('kerberos: authenticated user %s from %s', username, req.environ.get('REMOTE_ADDR')) # Pass on the GSS response in the Bottle response. response.set_header('WWW-Authenticate', 'Negotiate ' + str(gss_key)) # Clean up. kerberos.authGSSServerClean(context) return app(*app_args, **app_kwargs) else: return self.auth_fail()
def __call__(self, environ, start_response): def error(): start_response('500 Error', [ ('content-type', 'text/plain'), ]) return ['Internal error'] def noauth(msg=None): start_response('401 Unauthorized', [ ('content-type', 'text/plain'), ('WWW-Authenticate', 'Negotiate'), ('WWW-Authenticate', 'Basic realm="Web Service for CloudLab"') ]) if msg: return ['No auth. Error: %s' % msg] return ['No auth'] if 'HTTP_AUTHORIZATION' not in environ: return noauth() type, authstr = environ['HTTP_AUTHORIZATION'].split(' ', 1) if type == 'Negotiate': result, context = kerberos.authGSSServerInit(self.service) if result != 1: return error() gssstring = '' r = kerberos.authGSSServerStep(context, authstr) if r == 1: gssstring = kerberos.authGSSServerResponse(context) else: return noauth() def new_start_response(status, headers): start_response( status, [('WWW-Authenticate', 'Negotiate %s' % gssstring)] + headers) environ['REMOTE_USER'] = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) elif type == 'Basic': username, password = b64decode(authstr).split(':', 1) try: kerberos.checkPassword(username, password, self.service, self.realm) except Exception, e: return noauth(e.message) new_start_response = start_response environ['REMOTE_USER'] = username
async def authenticate(self, handler, data): auth_header = handler.request.headers.get('Authorization') if not auth_header: # pragma: nocover self.log.error("authenticate hit with no kerberos credentials, " "this code path should never occur") return None auth_type, auth_key = auth_header.split(" ", 1) if auth_type != 'Negotiate': # pragma: nocover self.log.error("authenticate hit with no kerberos credentials, " "this code path should never occur") return None gss_context = None try: # Initialize kerberos context rc, gss_context = kerberos.authGSSServerInit(self.service_name) # NOTE: Per the pykerberos documentation, the return code should be # checked after each step. However, after reading the pykerberos # code no method used here will ever return anything but # AUTH_GSS_COMPLETE (all other cases will raise an exception). We # keep these checks in just in case pykerberos changes its behavior # to match its docs, but they likely never will trigger. if rc != kerberos.AUTH_GSS_COMPLETE: # pragma: nocover self.log.error("GSS server init failed, return code = %r", rc) return None # Challenge step rc = kerberos.authGSSServerStep(gss_context, auth_key) if rc != kerberos.AUTH_GSS_COMPLETE: # pragma: nocover # Only warn here, since this happens for any user failing login self.log.warn("GSS server step failed, return code = %r", rc) return None gss_key = kerberos.authGSSServerResponse(gss_context) # Retrieve user name fulluser = kerberos.authGSSServerUserName(gss_context) user = fulluser.split("@", 1)[0] # Complete the protocol by responding with the Negotiate header handler.set_header('WWW-Authenticate', "Negotiate %s" % gss_key) return user except kerberos.GSSError as err: # pragma: nocover self.log.error("Error occurred during kerberos authentication", exc_info=err) return None finally: if gss_context is not None: kerberos.authGSSServerClean(gss_context)
def __call__(self, environ, start_response): def error(): start_response('500 Error', [ ('content-type', 'text/plain'), ]) return ['Internal error'] def noauth(): start_response('401 Unauthorized', [ ('content-type', 'text/plain'), ('WWW-Authenticate','Negotiate'), ('WWW-Authenticate','Basic realm="Secured area"') ]) return ['No auth'] if 'HTTP_AUTHORIZATION' not in environ: return noauth() type, authstr = environ['HTTP_AUTHORIZATION'].split(' ', 1) if type == 'Negotiate': result, context = kerberos.authGSSServerInit(self.service) if result != 1: return error() gssstring='' r=kerberos.authGSSServerStep(context,authstr) if r == 1: gssstring=kerberos.authGSSServerResponse(context) else: return noauth() def new_start_response(status, headers): start_response( status, [ ('WWW-Authenticate','Negotiate %s' % gssstring) ]+headers ) environ['REMOTE_USER']=kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) elif type == 'Basic': username, password = b64decode(authstr).split(':',1) try: kerberos.checkPassword(username, password, self.service, self.realm) except: return noauth() new_start_response=start_response environ['REMOTE_USER']=username return self.wrapped(environ, new_start_response)
def __call__(self, environ, start_response): def error(): start_response("500 Error", [("content-type", "text/plain")]) return ["Internal error"] def noauth(msg=None): start_response( "401 Unauthorized", [ ("content-type", "text/plain"), ("WWW-Authenticate", "Negotiate"), ("WWW-Authenticate", 'Basic realm="Web Service for CloudLab"'), ], ) if msg: return ["No auth. Error: %s" % msg] return ["No auth"] if "HTTP_AUTHORIZATION" not in environ: return noauth() type, authstr = environ["HTTP_AUTHORIZATION"].split(" ", 1) if type == "Negotiate": result, context = kerberos.authGSSServerInit(self.service) if result != 1: return error() gssstring = "" r = kerberos.authGSSServerStep(context, authstr) if r == 1: gssstring = kerberos.authGSSServerResponse(context) else: return noauth() def new_start_response(status, headers): start_response(status, [("WWW-Authenticate", "Negotiate %s" % gssstring)] + headers) environ["REMOTE_USER"] = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) elif type == "Basic": username, password = b64decode(authstr).split(":", 1) try: kerberos.checkPassword(username, password, self.service, self.realm) except Exception, e: return noauth(e.message) new_start_response = start_response environ["REMOTE_USER"] = username
def verify_token(self, logger, token): """ Method used to verify token against KDC :param token: Base64 encoded token (don't decoded it) :return If authentication succeed, dict with {'token_resp':the base64 encoded reponse from KDC, 'user':username of client} """ # Initialize context with service res = dict() username = "" try: result, context = authGSSServerInit("HTTP@" + self.krb5_service) if result != 1: logger.error( "KerberosClient::verify_token: authGSSServerInit(HTTP@{}) failed with status code : {}" .format(str(self.krb5_service), str(result))) return res result = authGSSServerStep(context, token) if result != 1: logger.error( "KerberosClient::verify_token: authGSSServerStep(token) failed with status code : {}" .format(str(result))) return res # Retrieve username of authenticated user username = authGSSServerUserName(context) # Retrieve KDC response kdc_response = authGSSServerResponse(context) # Clean kerberos context authGSSServerClean(context) except Exception as e: logger.error( "KerberosClient::verify_token: Verify token against KDC failed : {}" .format(str(e))) return res logger.info( "KerberosClient::verify_token: Successfull authentication for username {}" .format(username)) return { 'dn': username, 'user_phone': 'N/A', 'user_email': username if '@' in username else username + '@' + self.realm, 'password_expired': False, 'account_locked': False, 'token_resp': kdc_response }
async def authenticate(self, request): import kerberos auth_header = request.headers.get("Authorization") if not auth_header: raise unauthorized("Negotiate") auth_type, auth_key = auth_header.split(" ", 1) if auth_type != "Negotiate": raise unauthorized("Negotiate") gss_context = None try: # Initialize kerberos context rc, gss_context = kerberos.authGSSServerInit(self.service_name) # NOTE: Per the pykerberos documentation, the return code should be # checked after each step. However, after reading the pykerberos # code no method used here will ever return anything but # AUTH_GSS_COMPLETE (all other cases will raise an exception). We # keep these checks in just in case pykerberos changes its behavior # to match its docs, but they likely never will trigger. if rc != kerberos.AUTH_GSS_COMPLETE: self.raise_auth_error( "GSS server init failed, return code = %r" % rc) # Challenge step rc = kerberos.authGSSServerStep(gss_context, auth_key) if rc != kerberos.AUTH_GSS_COMPLETE: self.raise_auth_error( "GSS server step failed, return code = %r" % rc) gss_key = kerberos.authGSSServerResponse(gss_context) # Retrieve user name fulluser = kerberos.authGSSServerUserName(gss_context) user = fulluser.split("@", 1)[0] except kerberos.GSSError as err: self.raise_auth_error(err) finally: if gss_context is not None: kerberos.authGSSServerClean(gss_context) return User(user), gss_key
def testGSSAPI(service): def statusText(r): if r == 1: return "Complete" elif r == 0: return "Continue" else: return "Error" rc, vc = kerberos.authGSSClientInit(service) print("Status for authGSSClientInit = %s" % statusText(rc)) if rc != 1: return rs, vs = kerberos.authGSSServerInit(service) print("Status for authGSSServerInit = %s" % statusText(rs)) if rs != 1: return rc = kerberos.authGSSClientStep(vc, "") print("Status for authGSSClientStep = %s" % statusText(rc)) if rc != 0: return rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)) print("Status for authGSSServerStep = %s" % statusText(rs)) if rs == -1: return rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)) print("Status for authGSSClientStep = %s" % statusText(rc)) if rc == -1: return print("Server user name: %s" % kerberos.authGSSServerUserName(vs)) print("Server target name: %s" % kerberos.authGSSServerTargetName(vs)) print("Client user name: %s" % kerberos.authGSSClientUserName(vc)) rc = kerberos.authGSSClientClean(vc) print("Status for authGSSClientClean = %s" % statusText(rc)) rs = kerberos.authGSSServerClean(vs) print("Status for authGSSServerClean = %s" % statusText(rs))
def auth_negotiate(self, auth_header, callback): """ Perform Negotiate (GSSAPI/SSO) authentication via Kerberos. """ auth_str = auth_header.split()[1] # Initialize Kerberos Context result, context = kerberos.authGSSServerInit(self.settings["sso_service"]) if result != 1: raise tornado.web.HTTPError(500, "Kerberos Init failed") result = kerberos.authGSSServerStep(context, auth_str) if result == 1: gssstring = kerberos.authGSSServerResponse(context) else: # Fall back to Basic auth self.auth_basic(auth_header, callback) # NOTE: The user we get from Negotiate is a full UPN (e.g. user@REALM) user = kerberos.authGSSServerUserName(context) self.set_header("WWW-Authenticate", "Negotiate %s" % gssstring) kerberos.authGSSServerClean(context) callback(user)
def testGSSAPI(service): def statusText(r): if r == 1: return "Complete" elif r == 0: return "Continue" else: return "Error" rc, vc = kerberos.authGSSClientInit(service); print "Status for authGSSClientInit = %s" % statusText(rc); if rc != 1: return rs, vs = kerberos.authGSSServerInit(service); print "Status for authGSSServerInit = %s" % statusText(rs); if rs != 1: return rc = kerberos.authGSSClientStep(vc, ""); print "Status for authGSSClientStep = %s" % statusText(rc); if rc != 0: return rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)); print "Status for authGSSServerStep = %s" % statusText(rs); if rs == -1: return rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)); print "Status for authGSSClientStep = %s" % statusText(rc); if rc == -1: return print "Server user name: %s" % kerberos.authGSSServerUserName(vs); print "Server target name: %s" % kerberos.authGSSServerTargetName(vs); print "Client user name: %s" % kerberos.authGSSClientUserName(vc); rc = kerberos.authGSSClientClean(vc); print "Status for authGSSClientClean = %s" % statusText(rc); rs = kerberos.authGSSServerClean(vs); print "Status for authGSSServerClean = %s" % statusText(rs);
def get_kerberos_userid(request): if not request.authorization or request.authorization[0] != 'Negotiate': if 'challenge' in request.params: raise HTTPUnauthorized(headers={'WWW-Authenticate': 'Negotiate'}) return None ticket = request.authorization[1] log.debug("Kerberos ticket received: %s" % ticket) result, context = kerberos.authGSSServerInit(SERVICE) if result != 1: log.error("Could not initialize Kerberos GSS service.") return None try: if not kerberos.authGSSServerStep(context,ticket) == 1: return None except kerberos.GSSError, e: log.error("%s: GSSError %s" % (request.remote_addr, e)) return None
def _gssapi_authenticate(token): state = None ctx = stack.top try: return_code, state = kerberos.authGSSServerInit(_KERBEROS_SERVICE.service_name) if return_code != kerberos.AUTH_GSS_COMPLETE: return None return_code = kerberos.authGSSServerStep(state, token) if return_code == kerberos.AUTH_GSS_COMPLETE: ctx.kerberos_token = kerberos.authGSSServerResponse(state) ctx.kerberos_user = kerberos.authGSSServerUserName(state) return return_code if return_code == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE return None except kerberos.GSSError: return None finally: if state: kerberos.authGSSServerClean(state)
def get_kerberos_userid(request): if not request.authorization or request.authorization[0] != 'Negotiate': if 'challenge' in request.params: raise HTTPUnauthorized(headers={'WWW-Authenticate': 'Negotiate'}) return None ticket = request.authorization[1] log.debug("Kerberos ticket received: %s" % ticket) result, context = kerberos.authGSSServerInit(SERVICE) if result != 1: log.error("Could not initialize Kerberos GSS service.") return None try: if not kerberos.authGSSServerStep(context, ticket) == 1: return None except kerberos.GSSError, e: log.error("%s: GSSError %s" % (request.remote_addr, e)) return None
def extractCredentials( self, request ): """ Extract credentials from 'request'. """ creds = {} authorization = request._auth if authorization: try: result, context = kerberos.authGSSServerInit("HTTP") if result != 1: return creds gssstring='' authstr = authorization.split(" ")[1] r=kerberos.authGSSServerStep(context,authstr) if r == 1: gssstring=kerberos.authGSSServerResponse(context) else: # Something went horribly wrong, challenge again! self.challenge(request, request.response) # Return the status to user's browser - this is like an ack message request.response.addHeader('WWW-Authenticate','Negotiate %s' % gssstring) username = kerberos.authGSSServerUserName(context) creds['login'] = self.deriveUserName(username) creds['remote_host'] = request.getClientAddr() creds['kerberos'] = True # For caching request.SESSION.set("__login",creds['login']) request.SESSION.set("__remote_host",creds['remote_host']) request.SESSION.set("__kerberos",creds['kerberos']) kerberos.authGSSServerClean(context) except GSSError as e: print "GSSAPI error in extractCredentials :"+str(e) else: # Let's attempt to cache this login = request.SESSION.get("__login") remote_host = request.SESSION.get("__remote_host") kerbeross = request.SESSION.get("__kerberos") if login and remote_host and kerbeross and request.getClientAddr() == remote_host: creds['login'] = login creds['remote_host'] = remote_host creds['kerberos'] = kerbeross return creds
def _gssapi_authenticate(token): state = None ctx = stack.top try: rc, state = kerberos.authGSSServerInit(_SERVICE_NAME) if rc != kerberos.AUTH_GSS_COMPLETE: return None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: ctx.kerberos_token = kerberos.authGSSServerResponse(state) ctx.kerberos_user = kerberos.authGSSServerUserName(state) return rc elif rc == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE else: return None except kerberos.GSSError: return None finally: if state: kerberos.authGSSServerClean(state)
def _gssapi_authenticate(token, service_name): ''' Performs GSSAPI Negotiate Authentication Parameters: token (str): GSSAPI Authentication Token service_name (str): GSSAPI service name Returns: tuple of (str | None) username (str | None) GSSAPI token ''' state = None try: rc, state = kerberos.authGSSServerInit(service_name) if rc != kerberos.AUTH_GSS_COMPLETE: log.warn('Unable to initialize server context') return None, None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: log.debug('Completed GSSAPI negotiation') return ( kerberos.authGSSServerUserName(state), kerberos.authGSSServerResponse(state), ) elif rc == kerberos.AUTH_GSS_CONTINUE: log.debug('Continuing GSSAPI negotiation') return kerberos.AUTH_GSS_CONTINUE else: log.info('Unable to step server context') return None, None except kerberos.GSSError: log.info('Unable to authenticate', exc_info=True) return None, None finally: if state: kerberos.authGSSServerClean(state)
def _gssapi_authenticate(token): ''' Performs GSSAPI Negotiate Authentication On success also stashes the server response token for mutual authentication at the top of request context with the name kerberos_token, along with the authenticated user principal with the name kerberos_user. @param token: GSSAPI Authentication Token @type token: str @returns gssapi return code or None on failure @rtype: int or None ''' state = None ctx = stack.top try: rc, state = kerberos.authGSSServerInit(_SERVICE_NAME) if rc != kerberos.AUTH_GSS_COMPLETE: print("Authentication error. Could not init server. RC=%s" % rc) return None rc = kerberos.authGSSServerStep(state, token) if rc == kerberos.AUTH_GSS_COMPLETE: ctx.kerberos_token = kerberos.authGSSServerResponse(state) ctx.kerberos_user = kerberos.authGSSServerUserName(state) print("Authenticated user: %s" % ctx.kerberos_user) return rc elif rc == kerberos.AUTH_GSS_CONTINUE: return kerberos.AUTH_GSS_CONTINUE else: print("Authentication error. RC=%s" % rc) return None except kerberos.GSSError as exc: print("Authentication error: %s" % str(exc)) return None finally: if state: kerberos.authGSSServerClean(state)
def _doNegotiateAuth(self): _ignore_result, context = kerberos.authGSSServerInit("") try: self._getKerberosDetails() kerberos.authGSSServerStep(context, self.authToken) targetName = kerberos.authGSSServerTargetName(context) if targetName.lower() != self._kerberosPrincipal.lower(): raise Exception("Target name did not match local principal - %s vs %s" % (targetName, self._kerberosPrincipal)) response = kerberos.authGSSServerResponse(context) principal = kerberos.authGSSServerUserName(context) (user, realm) = principal.split("@", 1) if realm.lower() != self._kerberosRealm.lower(): raise Exception("Mismatched realms - %s vs %s" % (realm, self._kerberosRealm)) self.user = user self.page.responseHeaders.append(("WWW-Authenticate", "Negotiate %s" % response)) print "Did negotiate auth for %s" % self.user except: print "Failed negotiate auth" self.page.offerNegotiate = False raise finally: kerberos.authGSSServerClean(context)
def test_gssapi(): """ Return Code Values 0 = Continue 1 = Complete Other = Error """ service = "HTTP@%s" % hostname rc, vc = kerberos.authGSSClientInit(service) assert rc == 1, "authGSSClientInit = %d, expecting 1" % rc rs, vs = kerberos.authGSSServerInit(service) assert rs == 1, "authGSSServerInit = %d, expecting 1" % rs rc = kerberos.authGSSClientStep(vc, "") assert rc == 0, "authGSSClientStep = %d, expecting 0" % rc rs = kerberos.authGSSServerStep(vs, kerberos.authGSSClientResponse(vc)) assert rs != -1, "authGSSServerStep = %d, not expecting it to be -1" % rs rc = kerberos.authGSSClientStep(vc, kerberos.authGSSServerResponse(vs)) assert rc != -1, "authGSSClientStep = %d, not expecting it to be -1" % rc expected_username = "******" % (username, realm.upper()) server_user_name = kerberos.authGSSServerUserName(vs) assert server_user_name == expected_username, "Invalid server username returned" client_user_name = kerberos.authGSSClientUserName(vc) assert client_user_name == expected_username, "Invalid client username returned" server_target_name = kerberos.authGSSServerTargetName(vs) assert server_target_name is None, "Server target name is not None" rc = kerberos.authGSSClientClean(vc) assert rc == 1, "authGSSClientClean = %d, expecting it to be 0" % rc rs = kerberos.authGSSServerClean(vs) assert rs == 1, "authGSSServerClean = %d, expecting it to be 0" % rs
def step(self, authorization, request): """ Try to authenticate the client and if succesful authenticate ourself to the client. """ user = None if not self.enabled(): return (None, False) try: (neg, challenge) = authorization.split() if neg.lower().strip() != 'negotiate': return (None, False) self.log.debug("Negotiate header found, trying Kerberos") result, context = krb.authGSSServerInit(self.servicename) result = krb.authGSSServerStep(context, challenge) if result == -1: return (None, False) response = krb.authGSSServerResponse(context) # Client authenticated successfully, so authenticate to the client: request.queue_header("www-authenticate", "negotiate " + response) user = krb.authGSSServerUserName(context) self.log.debug("Negotiate: found user %s" % user) result = krb.authGSSServerClean(context) if result != 1: self.log.error("Failed to cleanup gss context") return (user, True) except krb.GSSError as err: self.log.error("gssapi error: %s", err) return None, False
def auth_negotiate(self, auth_header): """ Manages the Negotiate authorization process with kerberos. Returns the gss server response after the kerberos negotiation is complete. """ gssstring = None user = None context = None try: # Initialize the kerberos auth. This will # fail if the entries in the keytab are invalid. result, context = kerberos.authGSSServerInit('HTTP@{}'.format( settings.SPNEGO_HOSTNAME)) if result != 1: logging.error('Kerberos init failed.') raise NotAuthorized result = kerberos.authGSSServerStep(context, auth_header) if result == 1: gssstring = kerberos.authGSSServerResponse(context) else: # There's something wrong with our session ticket # We should've already raised a GSSError raise NotAuthorized # This will give us the username in <user>@<realm> format user = kerberos.authGSSServerUserName(context) except kerberos.GSSError as e: logging.error("Kerberos error: %s", e) raise NotAuthorized finally: if context: kerberos.authGSSServerClean(context) return (gssstring, user)
def process_request(self, request): """ The process_request() method needs to communicate some state to the process_response() method. The two options for this are to return an HttpResponse object or to modify the META headers in the request object. In order to ensure that all of the middleware is properly invoked, this code currently uses the later approach. The following headers are currently used: GSS-String: This means that GSS authentication was successful and that we need to pass this value for the WWW-Authenticate header in the response. Return-401: This means that the SPNEGO backend is in use, but we didn't get an AUTHORIZATION header from the client. The way that the protocol works (http://tools.ietf.org/html/rfc4559) is by having the first response to an un-authenticated request be a 401 with the WWW-Authenticate header set to Negotiate. This will cause the browser to re-try the request with the AUTHORIZATION header set. """ # AuthenticationMiddleware is required so that request.user exists. if not hasattr(request, 'user'): raise ImproperlyConfigured( "The Django remote user auth middleware requires the" " authentication middleware to be installed. Edit your" " MIDDLEWARE_CLASSES setting to insert" " 'django.contrib.auth.middleware.AuthenticationMiddleware'" " before the SpnegoUserMiddleware class.") if 'HTTP_AUTHORIZATION' in request.META: type, authstr = request.META['HTTP_AUTHORIZATION'].split(' ', 1) if type == 'Negotiate': try: result, context = kerberos.authGSSServerInit('HTTP') if result != 1: return gssstring = '' r = kerberos.authGSSServerStep(context, authstr) if r == 1: gssstring = kerberos.authGSSServerResponse(context) request.META['GSS-String'] = 'Negotiate %s' % gssstring else: kerberos.authGSSServerClean(context) return username = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) if request.user.is_authenticated(): if request.user.username == self.clean_username( username, request): return user = authenticate(username=username) if user: request.user = user login(request, user) return except: LOG.exception( 'Unexpected error when authenticating against KDC') return else: request.META['Return-401'] = '' return else: if not request.user.is_authenticated(): request.META['Return-401'] = '' return
def process_request(self, request): """ The process_request() method needs to communicate some state to the process_response() method. The two options for this are to return an HttpResponse object or to modify the META headers in the request object. In order to ensure that all of the middleware is properly invoked, this code currently uses the later approach. The following headers are currently used: GSS-String: This means that GSS authentication was successful and that we need to pass this value for the WWW-Authenticate header in the response. Return-401: This means that the SPNEGO backend is in use, but we didn't get an AUTHORIZATION header from the client. The way that the protocol works (http://tools.ietf.org/html/rfc4559) is by having the first response to an un-authenticated request be a 401 with the WWW-Authenticate header set to Negotiate. This will cause the browser to re-try the request with the AUTHORIZATION header set. """ view_func = resolve(request.path)[0] if view_func in DJANGO_VIEW_AUTH_WHITELIST: return # AuthenticationMiddleware is required so that request.user exists. if not hasattr(request, 'user'): raise exceptions.ImproperlyConfigured( "The Django remote user auth middleware requires the" " authentication middleware to be installed. Edit your" " MIDDLEWARE_CLASSES setting to insert" " 'django.contrib.auth.middleware.AuthenticationMiddleware'" " before the SpnegoUserMiddleware class.") if 'HTTP_AUTHORIZATION' in request.META: type, authstr = request.META['HTTP_AUTHORIZATION'].split(' ', 1) if type == 'Negotiate': try: result, context = kerberos.authGSSServerInit('HTTP') if result != 1: return gssstring = '' r = kerberos.authGSSServerStep(context, authstr) if r == 1: gssstring = kerberos.authGSSServerResponse(context) request.META['GSS-String'] = 'Negotiate %s' % gssstring else: kerberos.authGSSServerClean(context) return username = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) # In Trusted knox proxy, Hue must expect following: # Trusted knox user: KNOX_PRINCIPAL # Trusted knox proxy host: KNOX_PROXYHOSTS if 'desktop.auth.backend.KnoxSpnegoDjangoBackend' in AUTH.BACKEND.get( ): knox_verification = False principals = self.clean_principal( KNOX.KNOX_PRINCIPAL.get()) principal = self.clean_principal(username) if principal.intersection(principals): # This may contain chain of reverse proxies, e.g. knox proxy, hue load balancer # Compare hostname on both HTTP_X_FORWARDED_HOST & KNOX_PROXYHOSTS. # Both of these can be configured to use either hostname or IPs and we have to normalize to one or the other req_hosts = self.clean_host( request.META['HTTP_X_FORWARDED_HOST']) knox_proxy = self.clean_host( KNOX.KNOX_PROXYHOSTS.get()) if req_hosts.intersection(knox_proxy): knox_verification = True else: access_warn( request, 'Failed to verify provided host %s with %s ' % (req_hosts, knox_proxy)) else: access_warn( request, 'Failed to verify provided username %s with %s ' % (principal, principals)) # If knox authentication failed then generate 401 (Unauthorized error) if not knox_verification: request.META['Return-401'] = '' return if request.user.is_authenticated: if request.user.username == self.clean_username( username, request): return user = authenticate(username=username, request=request) if user: request.user = user login(request, user) msg = 'Successful login for user: %s' % request.user.username else: msg = 'Failed login for user: %s' % request.user.username request.audit = { 'operation': 'USER_LOGIN', 'username': request.user.username, 'operationText': msg } access_warn(request, msg) return except: LOG.exception( 'Unexpected error when authenticating against KDC') return else: request.META['Return-401'] = '' return else: if not request.user.is_authenticated: request.META['Return-401'] = '' return
def kerberos_authenticate(resource, req, resp, *args, **kwargs): # Try pre-emptive authentication if not req.auth: if optional: req.context["user"] = None return func(resource, req, resp, *args, **kwargs) logger.debug(u"No Kerberos ticket offered while attempting to access %s from %s", req.env["PATH_INFO"], req.context.get("remote_addr")) raise falcon.HTTPUnauthorized("Unauthorized", "No Kerberos ticket offered, are you sure you've logged in with domain user account?", ["Negotiate"]) token = ''.join(req.auth.split()[1:]) try: result, context = kerberos.authGSSServerInit("HTTP@" + const.FQDN) except kerberos.GSSError as ex: # TODO: logger.error raise falcon.HTTPForbidden("Forbidden", "Authentication System Failure: %s(%s)" % (ex.args[0][0], ex.args[1][0],)) try: result = kerberos.authGSSServerStep(context, token) except kerberos.GSSError as ex: kerberos.authGSSServerClean(context) logger.error(u"Kerberos authentication failed from %s. " "GSSAPI error: %s (%d), perhaps the clock skew it too large?", req.context.get("remote_addr"), ex.args[0][0], ex.args[0][1]) raise falcon.HTTPForbidden("Forbidden", "GSSAPI error: %s (%d), perhaps the clock skew it too large?" % (ex.args[0][0], ex.args[0][1])) except kerberos.KrbError as ex: kerberos.authGSSServerClean(context) logger.error(u"Kerberos authentication failed from %s. " "Kerberos error: %s (%d)", req.context.get("remote_addr"), ex.args[0][0], ex.args[0][1]) raise falcon.HTTPForbidden("Forbidden", "Kerberos error: %s" % (ex.args[0],)) user = kerberos.authGSSServerUserName(context) if "$@" in user and optional: # Extract machine hostname # TODO: Assert LDAP group membership req.context["machine"], _ = user.lower().split("$@", 1) req.context["user"] = None else: # Attempt to look up real user req.context["user"] = User.objects.get(user) try: kerberos.authGSSServerClean(context) except kerberos.GSSError as ex: logger.error(u"Kerberos authentication failed for user %s from %s. " "Authentication system failure: %s (%d)", user, req.context.get("remote_addr"), ex.args[0][0], ex.args[0][1]) raise falcon.HTTPUnauthorized("Authentication System Failure %s (%s)" % (ex.args[0][0], ex.args[1][0])) if result == kerberos.AUTH_GSS_COMPLETE: logger.debug(u"Succesfully authenticated user %s for %s from %s", req.context["user"], req.env["PATH_INFO"], req.context["remote_addr"]) return func(resource, req, resp, *args, **kwargs) elif result == kerberos.AUTH_GSS_CONTINUE: logger.error(u"Kerberos authentication failed for user %s from %s. " "Unauthorized, tried GSSAPI.", user, req.context.get("remote_addr")) raise falcon.HTTPUnauthorized("Unauthorized", "Tried GSSAPI") else: logger.error(u"Kerberos authentication failed for user %s from %s. " "Forbidden, tried GSSAPI.", user, req.context.get("remote_addr")) raise falcon.HTTPForbidden("Forbidden", "Tried GSSAPI")
def process_request(self, request): """ The process_request() method needs to communicate some state to the process_response() method. The two options for this are to return an HttpResponse object or to modify the META headers in the request object. In order to ensure that all of the middleware is properly invoked, this code currently uses the later approach. The following headers are currently used: GSS-String: This means that GSS authentication was successful and that we need to pass this value for the WWW-Authenticate header in the response. Return-401: This means that the SPNEGO backend is in use, but we didn't get an AUTHORIZATION header from the client. The way that the protocol works (http://tools.ietf.org/html/rfc4559) is by having the first response to an un-authenticated request be a 401 with the WWW-Authenticate header set to Negotiate. This will cause the browser to re-try the request with the AUTHORIZATION header set. """ # AuthenticationMiddleware is required so that request.user exists. if not hasattr(request, 'user'): raise ImproperlyConfigured( "The Django remote user auth middleware requires the" " authentication middleware to be installed. Edit your" " MIDDLEWARE_CLASSES setting to insert" " 'django.contrib.auth.middleware.AuthenticationMiddleware'" " before the SpnegoUserMiddleware class.") if 'HTTP_AUTHORIZATION' in request.META: type, authstr = request.META['HTTP_AUTHORIZATION'].split(' ', 1) if type == 'Negotiate': try: result, context = kerberos.authGSSServerInit('HTTP') if result != 1: return gssstring='' r=kerberos.authGSSServerStep(context,authstr) if r == 1: gssstring=kerberos.authGSSServerResponse(context) request.META['GSS-String'] = 'Negotiate %s' % gssstring else: kerberos.authGSSServerClean(context) return username = kerberos.authGSSServerUserName(context) kerberos.authGSSServerClean(context) if request.user.is_authenticated(): if request.user.username == self.clean_username(username, request): return user = authenticate(username=username) if user: request.user = user login(request, user) return except: LOG.exception('Unexpected error when authenticating against KDC') return else: request.META['Return-401'] = '' return else: if not request.user.is_authenticated(): request.META['Return-401'] = '' return