|
|
ac7d03 |
From d1a482316296d32551470de698a1bdd6a7efed1a Mon Sep 17 00:00:00 2001
|
|
|
ac7d03 |
From: Simo Sorce <simo@redhat.com>
|
|
|
ac7d03 |
Date: Wed, 22 Mar 2017 18:38:22 -0400
|
|
|
ac7d03 |
Subject: [PATCH] Handle failed authentication via cookie
|
|
|
ac7d03 |
|
|
|
ac7d03 |
If cookie authentication fails and we get back a 401 see if we
|
|
|
ac7d03 |
tried a SPNEGO auth by checking if we had a GSSAPI context. If not
|
|
|
ac7d03 |
it means our session cookie was invalid or expired or some other
|
|
|
ac7d03 |
error happened on the server that requires us to try a full SPNEGO
|
|
|
ac7d03 |
handshake, so go ahead and try it.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Fixes https://pagure.io/freeipa/issue/6775
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Signed-off-by: Simo Sorce <simo@redhat.com>
|
|
|
ac7d03 |
Reviewed-By: Christian Heimes <cheimes@redhat.com>
|
|
|
ac7d03 |
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
|
|
ac7d03 |
---
|
|
|
ac7d03 |
ipalib/rpc.py | 52 ++++++++++++++++++++++++++++++++--------------------
|
|
|
ac7d03 |
1 file changed, 32 insertions(+), 20 deletions(-)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
|
|
|
ac7d03 |
index 38321d17cf2c9529738aa45cc44bbd38b08b032b..c1ceeec197c4a9c55f303f0fd431e86adb389598 100644
|
|
|
ac7d03 |
--- a/ipalib/rpc.py
|
|
|
ac7d03 |
+++ b/ipalib/rpc.py
|
|
|
ac7d03 |
@@ -586,22 +586,33 @@ class KerbTransport(SSLTransport):
|
|
|
ac7d03 |
else:
|
|
|
ac7d03 |
raise errors.KerberosError(message=unicode(e))
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- def get_host_info(self, host):
|
|
|
ac7d03 |
+ def _get_host(self):
|
|
|
ac7d03 |
+ return self._connection[0]
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ def _remove_extra_header(self, name):
|
|
|
ac7d03 |
+ for (h, v) in self._extra_headers:
|
|
|
ac7d03 |
+ if h == name:
|
|
|
ac7d03 |
+ self._extra_headers.remove((h, v))
|
|
|
ac7d03 |
+ break
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ def get_auth_info(self, use_cookie=True):
|
|
|
ac7d03 |
"""
|
|
|
ac7d03 |
Two things can happen here. If we have a session we will add
|
|
|
ac7d03 |
a cookie for that. If not we will set an Authorization header.
|
|
|
ac7d03 |
"""
|
|
|
ac7d03 |
- (host, extra_headers, x509) = SSLTransport.get_host_info(self, host)
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- if not isinstance(extra_headers, list):
|
|
|
ac7d03 |
- extra_headers = []
|
|
|
ac7d03 |
+ if not isinstance(self._extra_headers, list):
|
|
|
ac7d03 |
+ self._extra_headers = []
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- session_cookie = getattr(context, 'session_cookie', None)
|
|
|
ac7d03 |
- if session_cookie:
|
|
|
ac7d03 |
- extra_headers.append(('Cookie', session_cookie))
|
|
|
ac7d03 |
- return (host, extra_headers, x509)
|
|
|
ac7d03 |
+ # Remove any existing Cookie first
|
|
|
ac7d03 |
+ self._remove_extra_header('Cookie')
|
|
|
ac7d03 |
+ if use_cookie:
|
|
|
ac7d03 |
+ session_cookie = getattr(context, 'session_cookie', None)
|
|
|
ac7d03 |
+ if session_cookie:
|
|
|
ac7d03 |
+ self._extra_headers.append(('Cookie', session_cookie))
|
|
|
ac7d03 |
+ return
|
|
|
ac7d03 |
|
|
|
ac7d03 |
# Set the remote host principal
|
|
|
ac7d03 |
+ host = self._get_host()
|
|
|
ac7d03 |
service = self.service + "@" + host.split(':')[0]
|
|
|
ac7d03 |
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
@@ -616,18 +627,14 @@ class KerbTransport(SSLTransport):
|
|
|
ac7d03 |
except gssapi.exceptions.GSSError as e:
|
|
|
ac7d03 |
self._handle_exception(e, service=service)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- self._set_auth_header(extra_headers, response)
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- return (host, extra_headers, x509)
|
|
|
ac7d03 |
+ self._set_auth_header(response)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- def _set_auth_header(self, extra_headers, token):
|
|
|
ac7d03 |
- for (h, v) in extra_headers:
|
|
|
ac7d03 |
- if h == 'Authorization':
|
|
|
ac7d03 |
- extra_headers.remove((h, v))
|
|
|
ac7d03 |
- break
|
|
|
ac7d03 |
+ def _set_auth_header(self, token):
|
|
|
ac7d03 |
+ # Remove any existing authorization header first
|
|
|
ac7d03 |
+ self._remove_extra_header('Authorization')
|
|
|
ac7d03 |
|
|
|
ac7d03 |
if token:
|
|
|
ac7d03 |
- extra_headers.append(
|
|
|
ac7d03 |
+ self._extra_headers.append(
|
|
|
ac7d03 |
('Authorization', 'negotiate %s' % base64.b64encode(token).decode('ascii'))
|
|
|
ac7d03 |
)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
@@ -651,18 +658,23 @@ class KerbTransport(SSLTransport):
|
|
|
ac7d03 |
if self._sec_context.complete:
|
|
|
ac7d03 |
self._sec_context = None
|
|
|
ac7d03 |
return True
|
|
|
ac7d03 |
- self._set_auth_header(self._extra_headers, token)
|
|
|
ac7d03 |
+ self._set_auth_header(token)
|
|
|
ac7d03 |
+ return False
|
|
|
ac7d03 |
+ elif response.status == 401:
|
|
|
ac7d03 |
+ self.get_auth_info(use_cookie=False)
|
|
|
ac7d03 |
return False
|
|
|
ac7d03 |
return True
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def single_request(self, host, handler, request_body, verbose=0):
|
|
|
ac7d03 |
# Based on Python 2.7's xmllib.Transport.single_request
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
- h = SSLTransport.make_connection(self, host)
|
|
|
ac7d03 |
+ h = self.make_connection(host)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
if verbose:
|
|
|
ac7d03 |
h.set_debuglevel(1)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ self.get_auth_info()
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
while True:
|
|
|
ac7d03 |
if six.PY2:
|
|
|
ac7d03 |
# pylint: disable=no-value-for-parameter
|
|
|
ac7d03 |
--
|
|
|
ac7d03 |
2.12.1
|
|
|
ac7d03 |
|