diff options
author | Jeff Forcier <jeff@bitprophet.org> | 2017-09-12 13:12:37 -0700 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2017-09-12 13:12:37 -0700 |
commit | c4aed573db0392ec35f1dbe3d4ba6aa0b25f8815 (patch) | |
tree | 9d6f080a6a088ca3ca15f6babc2ba33660d441ec /paramiko/auth_handler.py | |
parent | d446cf23c2a7765e3f4b3202f3dc3cba4c3b5c45 (diff) | |
parent | 20e0285628cd5f075b6f81c897a440e2eb5da95e (diff) | |
download | paramiko-c4aed573db0392ec35f1dbe3d4ba6aa0b25f8815.tar.gz |
Merge branch '2.1' into 2.2
Diffstat (limited to 'paramiko/auth_handler.py')
-rw-r--r-- | paramiko/auth_handler.py | 195 |
1 files changed, 138 insertions, 57 deletions
diff --git a/paramiko/auth_handler.py b/paramiko/auth_handler.py index ae88179e..ac6e23da 100644 --- a/paramiko/auth_handler.py +++ b/paramiko/auth_handler.py @@ -44,7 +44,7 @@ from paramiko.ssh_exception import ( PartialAuthentication, ) from paramiko.server import InteractiveQuery -from paramiko.ssh_gss import GSSAuth +from paramiko.ssh_gss import GSSAuth, GSS_EXCEPTIONS class AuthHandler (object): @@ -269,19 +269,26 @@ class AuthHandler (object): mech = m.get_string() m = Message() m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN) - m.add_string(sshgss.ssh_init_sec_context(self.gss_host, - mech, - self.username,)) + try: + m.add_string(sshgss.ssh_init_sec_context( + self.gss_host, + mech, + self.username,)) + except GSS_EXCEPTIONS as e: + return self._handle_local_gss_failure(e) self.transport._send_message(m) while True: ptype, m = self.transport.packetizer.read_message() if ptype == MSG_USERAUTH_GSSAPI_TOKEN: srv_token = m.get_string() - next_token = sshgss.ssh_init_sec_context( - self.gss_host, - mech, - self.username, - srv_token) + try: + next_token = sshgss.ssh_init_sec_context( + self.gss_host, + mech, + self.username, + srv_token) + except GSS_EXCEPTIONS as e: + return self._handle_local_gss_failure(e) # After this step the GSSAPI should not return any # token. If it does, we keep sending the token to # the server until no more token is returned. @@ -309,7 +316,7 @@ class AuthHandler (object): maj_status = m.get_int() min_status = m.get_int() err_msg = m.get_string() - m.get_string() # Lang tag - discarded + m.get_string() # Lang tag - discarded raise SSHException("GSS-API Error:\nMajor Status: %s\n\ Minor Status: %s\ \nError Message:\ %s\n") % (str(maj_status), @@ -402,7 +409,7 @@ class AuthHandler (object): (self.auth_username != username)): self.transport._log( WARNING, - 'Auth rejected because the client attempted to change username in mid-flight' # noqa + 'Auth rejected because the client attempted to change username in mid-flight' # noqa ) self._disconnect_no_more_auth() return @@ -510,52 +517,16 @@ class AuthHandler (object): supported_mech = sshgss.ssh_gss_oids("server") # RFC 4462 says we are not required to implement GSS-API error # messages. See section 3.8 in http://www.ietf.org/rfc/rfc4462.txt - while True: - m = Message() - m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE) - m.add_bytes(supported_mech) - self.transport._send_message(m) - ptype, m = self.transport.packetizer.read_message() - if ptype == MSG_USERAUTH_GSSAPI_TOKEN: - client_token = m.get_string() - # use the client token as input to establish a secure - # context. - try: - token = sshgss.ssh_accept_sec_context(self.gss_host, - client_token, - username) - except Exception: - result = AUTH_FAILED - self._send_auth_result(username, method, result) - raise - if token is not None: - m = Message() - m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN) - m.add_string(token) - self.transport._send_message(m) - else: - result = AUTH_FAILED - self._send_auth_result(username, method, result) - return - # check MIC - ptype, m = self.transport.packetizer.read_message() - if ptype == MSG_USERAUTH_GSSAPI_MIC: - break - mic_token = m.get_string() - try: - sshgss.ssh_check_mic(mic_token, - self.transport.session_id, - username) - except Exception: - result = AUTH_FAILED - self._send_auth_result(username, method, result) - raise - # TODO: Implement client credential saving. - # The OpenSSH server is able to create a TGT with the delegated - # client credentials, but this is not supported by GSS-API. - result = AUTH_SUCCESSFUL - self.transport.server_object.check_auth_gssapi_with_mic( - username, result) + m = Message() + m.add_byte(cMSG_USERAUTH_GSSAPI_RESPONSE) + m.add_bytes(supported_mech) + self.transport.auth_handler = GssapiWithMicAuthHandler(self, + sshgss) + self.transport._expected_packet = (MSG_USERAUTH_GSSAPI_TOKEN, + MSG_USERAUTH_REQUEST, + MSG_SERVICE_REQUEST) + self.transport._send_message(m) + return elif method == "gssapi-keyex" and gss_auth: mic_token = m.get_string() sshgss = self.transport.kexgss_ctxt @@ -655,6 +626,17 @@ class AuthHandler (object): self._send_auth_result( self.auth_username, 'keyboard-interactive', result) + def _handle_local_gss_failure(self, e): + self.transport.saved_exception = e + self.transport._log(DEBUG, "GSSAPI failure: %s" % str(e)) + self.transport._log(INFO, 'Authentication (%s) failed.' % + self.auth_method) + self.authenticated = False + self.username = None + if self.auth_event is not None: + self.auth_event.set() + return + _handler_table = { MSG_SERVICE_REQUEST: _parse_service_request, MSG_SERVICE_ACCEPT: _parse_service_accept, @@ -665,3 +647,102 @@ class AuthHandler (object): MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request, MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, } + + +class GssapiWithMicAuthHandler(object): + """A specialized Auth handler for gssapi-with-mic + + During the GSSAPI token exchange we need a modified dispatch table, + because the packet type numbers are not unique. + """ + + method = "gssapi-with-mic" + + def __init__(self, delegate, sshgss): + self._delegate = delegate + self.sshgss = sshgss + + def abort(self): + self._restore_delegate_auth_handler() + return self._delegate.abort() + + @property + def transport(self): + return self._delegate.transport + + @property + def _send_auth_result(self): + return self._delegate._send_auth_result + + @property + def auth_username(self): + return self._delegate.auth_username + + @property + def gss_host(self): + return self._delegate.gss_host + + def _restore_delegate_auth_handler(self): + self.transport.auth_handler = self._delegate + + def _parse_userauth_gssapi_token(self, m): + client_token = m.get_string() + # use the client token as input to establish a secure + # context. + sshgss = self.sshgss + try: + token = sshgss.ssh_accept_sec_context(self.gss_host, + client_token, + self.auth_username) + except Exception as e: + self.transport.saved_exception = e + result = AUTH_FAILED + self._restore_delegate_auth_handler() + self._send_auth_result(self.auth_username, self.method, result) + raise + if token is not None: + m = Message() + m.add_byte(cMSG_USERAUTH_GSSAPI_TOKEN) + m.add_string(token) + self.transport._expected_packet = (MSG_USERAUTH_GSSAPI_TOKEN, + MSG_USERAUTH_GSSAPI_MIC, + MSG_USERAUTH_REQUEST) + self.transport._send_message(m) + + def _parse_userauth_gssapi_mic(self, m): + mic_token = m.get_string() + sshgss = self.sshgss + username = self.auth_username + self._restore_delegate_auth_handler() + try: + sshgss.ssh_check_mic(mic_token, + self.transport.session_id, + username) + except Exception as e: + self.transport.saved_exception = e + result = AUTH_FAILED + self._send_auth_result(username, self.method, result) + raise + # TODO: Implement client credential saving. + # The OpenSSH server is able to create a TGT with the delegated + # client credentials, but this is not supported by GSS-API. + result = AUTH_SUCCESSFUL + self.transport.server_object.check_auth_gssapi_with_mic(username, + result) + # okay, send result + self._send_auth_result(username, self.method, result) + + def _parse_service_request(self, m): + self._restore_delegate_auth_handler() + return self._delegate._parse_service_request(m) + + def _parse_userauth_request(self, m): + self._restore_delegate_auth_handler() + return self._delegate._parse_userauth_request(m) + + _handler_table = { + MSG_SERVICE_REQUEST: _parse_service_request, + MSG_USERAUTH_REQUEST: _parse_userauth_request, + MSG_USERAUTH_GSSAPI_TOKEN: _parse_userauth_gssapi_token, + MSG_USERAUTH_GSSAPI_MIC: _parse_userauth_gssapi_mic, + } |