summaryrefslogtreecommitdiff
path: root/paramiko/auth_handler.py
diff options
context:
space:
mode:
authorJeff Forcier <jeff@bitprophet.org>2017-09-12 13:12:37 -0700
committerJeff Forcier <jeff@bitprophet.org>2017-09-12 13:12:37 -0700
commitc4aed573db0392ec35f1dbe3d4ba6aa0b25f8815 (patch)
tree9d6f080a6a088ca3ca15f6babc2ba33660d441ec /paramiko/auth_handler.py
parentd446cf23c2a7765e3f4b3202f3dc3cba4c3b5c45 (diff)
parent20e0285628cd5f075b6f81c897a440e2eb5da95e (diff)
downloadparamiko-c4aed573db0392ec35f1dbe3d4ba6aa0b25f8815.tar.gz
Merge branch '2.1' into 2.2
Diffstat (limited to 'paramiko/auth_handler.py')
-rw-r--r--paramiko/auth_handler.py195
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,
+ }