[Freeipa-devel] [freeipa PR#649][synchronized] Session cookie storage and handling fixes

2017-03-24 Thread simo5
   URL: https://github.com/freeipa/freeipa/pull/649
Author: simo5
 Title: #649: Session cookie storage and handling fixes
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/649/head:pr649
git checkout pr649
From 9fd0b4ce68daac2edbc38ccc743d4b7c1fafdf9d Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:25:38 -0400
Subject: [PATCH 1/4] Avoid growing FILE ccaches unnecessarily

Related https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipapython/session_storage.py | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index bcf0947..f208827 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -111,6 +111,12 @@ def store_data(princ_name, key, value):
 if not isinstance(value, bytes):
 value = value.encode('utf-8')
 
+# FILE ccaches grow every time an entry is stored, so we need
+# to avoid storing the same entry multiple times.
+oldvalue = get_data(princ_name, key)
+if oldvalue == value:
+return
+
 context = krb5_context()
 principal = krb5_principal()
 ccache = krb5_ccache()

From 7653192d67de8d6b19259ece49f6c1d31f788665 Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:38:22 -0400
Subject: [PATCH 2/4] Handle failed authentication via cookie

If cookie authentication fails and we get back a 401 see if we
tried a SPNEGO auth by checking if we had a GSSAPI context. If not
it means our session cookie was invalid or expired or some other
error happened on the server that requires us to try a full SPNEGO
handshake, so go ahead and try it.

Fixes https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipalib/rpc.py | 52 
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 303b22a..f597ce0 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -586,22 +586,33 @@ def _handle_exception(self, e, service=None):
 else:
 raise errors.KerberosError(message=unicode(e))
 
-def get_host_info(self, host):
+def _get_host(self):
+return self._connection[0]
+
+def _remove_extra_header(self, name):
+for (h, v) in self._extra_headers:
+if h == name:
+self._extra_headers.remove((h, v))
+break
+
+def get_auth_info(self, use_cookie=True):
 """
 Two things can happen here. If we have a session we will add
 a cookie for that. If not we will set an Authorization header.
 """
-(host, extra_headers, x509) = SSLTransport.get_host_info(self, host)
-
-if not isinstance(extra_headers, list):
-extra_headers = []
+if not isinstance(self._extra_headers, list):
+self._extra_headers = []
 
-session_cookie = getattr(context, 'session_cookie', None)
-if session_cookie:
-extra_headers.append(('Cookie', session_cookie))
-return (host, extra_headers, x509)
+# Remove any existing Cookie first
+self._remove_extra_header('Cookie')
+if use_cookie:
+session_cookie = getattr(context, 'session_cookie', None)
+if session_cookie:
+self._extra_headers.append(('Cookie', session_cookie))
+return
 
 # Set the remote host principal
+host = self._get_host()
 service = self.service + "@" + host.split(':')[0]
 
 try:
@@ -616,18 +627,14 @@ def get_host_info(self, host):
 except gssapi.exceptions.GSSError as e:
 self._handle_exception(e, service=service)
 
-self._set_auth_header(extra_headers, response)
-
-return (host, extra_headers, x509)
+self._set_auth_header(response)
 
-def _set_auth_header(self, extra_headers, token):
-for (h, v) in extra_headers:
-if h == 'Authorization':
-extra_headers.remove((h, v))
-break
+def _set_auth_header(self, token):
+# Remove any existing authorization header first
+self._remove_extra_header('Authorization')
 
 if token:
-extra_headers.append(
+self._extra_headers.append(
 ('Authorization', 'negotiate %s' % base64.b64encode(token).decode('ascii'))
 )
 
@@ -651,18 +658,23 @@ def _auth_complete(self, response):
 if self._sec_context.complete:
 self._sec_context = None
 return True
-self._set_auth_header(self._extra_headers, token)
+self._set_auth_header(token)
+return False
+elif response.status == 401:
+self.get_auth_info(use_cookie=False)
 return False
 return True
 
 def single_request(self, host, handler, request_body, verbose=0):

[Freeipa-devel] [freeipa PR#649][synchronized] Session cookie storage and handling fixes

2017-03-24 Thread simo5
   URL: https://github.com/freeipa/freeipa/pull/649
Author: simo5
 Title: #649: Session cookie storage and handling fixes
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/649/head:pr649
git checkout pr649
From 9fd0b4ce68daac2edbc38ccc743d4b7c1fafdf9d Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:25:38 -0400
Subject: [PATCH 1/4] Avoid growing FILE ccaches unnecessarily

Related https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipapython/session_storage.py | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index bcf0947..f208827 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -111,6 +111,12 @@ def store_data(princ_name, key, value):
 if not isinstance(value, bytes):
 value = value.encode('utf-8')
 
+# FILE ccaches grow every time an entry is stored, so we need
+# to avoid storing the same entry multiple times.
+oldvalue = get_data(princ_name, key)
+if oldvalue == value:
+return
+
 context = krb5_context()
 principal = krb5_principal()
 ccache = krb5_ccache()

From 7653192d67de8d6b19259ece49f6c1d31f788665 Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:38:22 -0400
Subject: [PATCH 2/4] Handle failed authentication via cookie

If cookie authentication fails and we get back a 401 see if we
tried a SPNEGO auth by checking if we had a GSSAPI context. If not
it means our session cookie was invalid or expired or some other
error happened on the server that requires us to try a full SPNEGO
handshake, so go ahead and try it.

Fixes https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipalib/rpc.py | 52 
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 303b22a..f597ce0 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -586,22 +586,33 @@ def _handle_exception(self, e, service=None):
 else:
 raise errors.KerberosError(message=unicode(e))
 
-def get_host_info(self, host):
+def _get_host(self):
+return self._connection[0]
+
+def _remove_extra_header(self, name):
+for (h, v) in self._extra_headers:
+if h == name:
+self._extra_headers.remove((h, v))
+break
+
+def get_auth_info(self, use_cookie=True):
 """
 Two things can happen here. If we have a session we will add
 a cookie for that. If not we will set an Authorization header.
 """
-(host, extra_headers, x509) = SSLTransport.get_host_info(self, host)
-
-if not isinstance(extra_headers, list):
-extra_headers = []
+if not isinstance(self._extra_headers, list):
+self._extra_headers = []
 
-session_cookie = getattr(context, 'session_cookie', None)
-if session_cookie:
-extra_headers.append(('Cookie', session_cookie))
-return (host, extra_headers, x509)
+# Remove any existing Cookie first
+self._remove_extra_header('Cookie')
+if use_cookie:
+session_cookie = getattr(context, 'session_cookie', None)
+if session_cookie:
+self._extra_headers.append(('Cookie', session_cookie))
+return
 
 # Set the remote host principal
+host = self._get_host()
 service = self.service + "@" + host.split(':')[0]
 
 try:
@@ -616,18 +627,14 @@ def get_host_info(self, host):
 except gssapi.exceptions.GSSError as e:
 self._handle_exception(e, service=service)
 
-self._set_auth_header(extra_headers, response)
-
-return (host, extra_headers, x509)
+self._set_auth_header(response)
 
-def _set_auth_header(self, extra_headers, token):
-for (h, v) in extra_headers:
-if h == 'Authorization':
-extra_headers.remove((h, v))
-break
+def _set_auth_header(self, token):
+# Remove any existing authorization header first
+self._remove_extra_header('Authorization')
 
 if token:
-extra_headers.append(
+self._extra_headers.append(
 ('Authorization', 'negotiate %s' % base64.b64encode(token).decode('ascii'))
 )
 
@@ -651,18 +658,23 @@ def _auth_complete(self, response):
 if self._sec_context.complete:
 self._sec_context = None
 return True
-self._set_auth_header(self._extra_headers, token)
+self._set_auth_header(token)
+return False
+elif response.status == 401:
+self.get_auth_info(use_cookie=False)
 return False
 return True
 
 def single_request(self, host, handler, request_body, verbose=0):

[Freeipa-devel] [freeipa PR#649][synchronized] Session cookie storage and handling fixes

2017-03-23 Thread simo5
   URL: https://github.com/freeipa/freeipa/pull/649
Author: simo5
 Title: #649: Session cookie storage and handling fixes
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/649/head:pr649
git checkout pr649
From 9fd0b4ce68daac2edbc38ccc743d4b7c1fafdf9d Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:25:38 -0400
Subject: [PATCH 1/4] Avoid growing FILE ccaches unnecessarily

Related https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipapython/session_storage.py | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
index bcf0947..f208827 100644
--- a/ipapython/session_storage.py
+++ b/ipapython/session_storage.py
@@ -111,6 +111,12 @@ def store_data(princ_name, key, value):
 if not isinstance(value, bytes):
 value = value.encode('utf-8')
 
+# FILE ccaches grow every time an entry is stored, so we need
+# to avoid storing the same entry multiple times.
+oldvalue = get_data(princ_name, key)
+if oldvalue == value:
+return
+
 context = krb5_context()
 principal = krb5_principal()
 ccache = krb5_ccache()

From 7653192d67de8d6b19259ece49f6c1d31f788665 Mon Sep 17 00:00:00 2001
From: Simo Sorce 
Date: Wed, 22 Mar 2017 18:38:22 -0400
Subject: [PATCH 2/4] Handle failed authentication via cookie

If cookie authentication fails and we get back a 401 see if we
tried a SPNEGO auth by checking if we had a GSSAPI context. If not
it means our session cookie was invalid or expired or some other
error happened on the server that requires us to try a full SPNEGO
handshake, so go ahead and try it.

Fixes https://pagure.io/freeipa/issue/6775

Signed-off-by: Simo Sorce 
---
 ipalib/rpc.py | 52 
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 303b22a..f597ce0 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -586,22 +586,33 @@ def _handle_exception(self, e, service=None):
 else:
 raise errors.KerberosError(message=unicode(e))
 
-def get_host_info(self, host):
+def _get_host(self):
+return self._connection[0]
+
+def _remove_extra_header(self, name):
+for (h, v) in self._extra_headers:
+if h == name:
+self._extra_headers.remove((h, v))
+break
+
+def get_auth_info(self, use_cookie=True):
 """
 Two things can happen here. If we have a session we will add
 a cookie for that. If not we will set an Authorization header.
 """
-(host, extra_headers, x509) = SSLTransport.get_host_info(self, host)
-
-if not isinstance(extra_headers, list):
-extra_headers = []
+if not isinstance(self._extra_headers, list):
+self._extra_headers = []
 
-session_cookie = getattr(context, 'session_cookie', None)
-if session_cookie:
-extra_headers.append(('Cookie', session_cookie))
-return (host, extra_headers, x509)
+# Remove any existing Cookie first
+self._remove_extra_header('Cookie')
+if use_cookie:
+session_cookie = getattr(context, 'session_cookie', None)
+if session_cookie:
+self._extra_headers.append(('Cookie', session_cookie))
+return
 
 # Set the remote host principal
+host = self._get_host()
 service = self.service + "@" + host.split(':')[0]
 
 try:
@@ -616,18 +627,14 @@ def get_host_info(self, host):
 except gssapi.exceptions.GSSError as e:
 self._handle_exception(e, service=service)
 
-self._set_auth_header(extra_headers, response)
-
-return (host, extra_headers, x509)
+self._set_auth_header(response)
 
-def _set_auth_header(self, extra_headers, token):
-for (h, v) in extra_headers:
-if h == 'Authorization':
-extra_headers.remove((h, v))
-break
+def _set_auth_header(self, token):
+# Remove any existing authorization header first
+self._remove_extra_header('Authorization')
 
 if token:
-extra_headers.append(
+self._extra_headers.append(
 ('Authorization', 'negotiate %s' % base64.b64encode(token).decode('ascii'))
 )
 
@@ -651,18 +658,23 @@ def _auth_complete(self, response):
 if self._sec_context.complete:
 self._sec_context = None
 return True
-self._set_auth_header(self._extra_headers, token)
+self._set_auth_header(token)
+return False
+elif response.status == 401:
+self.get_auth_info(use_cookie=False)
 return False
 return True
 
 def single_request(self, host, handler, request_body, verbose=0):