Michael Pasternak has uploaded a new change for review. Change subject: sdk: session based authentication for /localhost is broken #916285 ......................................................................
sdk: session based authentication for /localhost is broken #916285 detailed explanation: ===================== REST-API introduced new functionality at #876641 to JSESSION based authentication, if HTTP header Prefer:persistent-auth is set and client sends the Authorization header as well, - will be re-initiated new JSESSION, what is made all clients sending both Prefer and Authorization headers to get authorised again using Authorization header and not JSESSION, correct behaviour is: ==================== 1. send Authorization & Prefer headers 2. store JSESSION returned in cookie 3. use for authorization Prefer header & JSESSION cookie disabling session based authentication: ====================================== 1. omit from request Prefer header 2. add Authorization header https://bugzilla.redhat.com/show_bug.cgi?id=916285 Change-Id: Ief0ed86c26c2e74b8cc8f46d68b01f904c50d0e2 Signed-off-by: Michael Pasternak <[email protected]> --- M src/ovirtsdk/infrastructure/proxy.py M src/ovirtsdk/web/connection.py 2 files changed, 68 insertions(+), 12 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine-sdk refs/changes/78/12578/1 diff --git a/src/ovirtsdk/infrastructure/proxy.py b/src/ovirtsdk/infrastructure/proxy.py index 4dd5188..c15a927 100644 --- a/src/ovirtsdk/infrastructure/proxy.py +++ b/src/ovirtsdk/infrastructure/proxy.py @@ -90,6 +90,7 @@ ''' The proxy to web connection ''' + def __init__(self, connections_pool, persistent_auth=True): ''' @param connections_pool: connections pool @@ -101,11 +102,26 @@ # In order to create the cookies adapter we need to extract from the # URL the host name, so that we can accept cookies only from that host: self._url = self.__connections_pool.get_url() - parsed_url = urlparse.urlparse(self._url) # Create the cookies policy and jar: - cookies_policy = cookielib.DefaultCookiePolicy(allowed_domains=[parsed_url.hostname]) + cookies_policy = cookielib.DefaultCookiePolicy( + strict_ns_domain=DefaultCookiePolicy.DomainStrictNoDots, + allowed_domains=self.__getAllowedDomains(self._url)) self._cookies_jar = cookielib.CookieJar(policy=cookies_policy) + + def __getAllowedDomains(self, url): + ''' + fetches allowed domains for cookie + ''' + + LOCAL_HOST = 'localhost' + parsed_url = urlparse.urlparse(url) + domains = [parsed_url.hostname] + + if parsed_url.hostname == LOCAL_HOST: + return domains.append(LOCAL_HOST + '.local') + + return domains def getConnectionsPool(self): ''' @@ -196,10 +212,7 @@ ''' try: # Add cookie headers as needed: - request_adapter = CookieJarAdapter(self._url, headers) - self._cookies_jar.set_policy( - cookielib.DefaultCookiePolicy( - strict_ns_domain=DefaultCookiePolicy.DomainStrictNoDots)) + request_adapter = CookieJarAdapter(self._url + url, headers) self._cookies_jar.add_cookie_header(request_adapter) # Every request except the last one should indicate that we prefer @@ -208,7 +221,14 @@ headers["Prefer"] = "persistent-auth" # Send the request and wait for the response: - conn.doRequest(method=method, url=url, body=body, headers=headers) + conn.doRequest( + method=method, + url=url, + body=body, + headers=headers, + no_auth=self._persistent_auth and \ + self.__isSetJsessionCookie(self._cookies_jar) + ) response = conn.getResponse() @@ -242,6 +262,19 @@ finally: conn.close() + def __isSetJsessionCookie(self, cookies_jar): + ''' + Checks if JSESSIONID cookie is set + + @param cookies_jar: cookies container + ''' + if cookies_jar and len(cookies_jar._cookies) > 0: + for key in cookies_jar._cookies.keys(): + if cookies_jar._cookies[key].has_key('/api') and \ + cookies_jar._cookies[key]['/api'].has_key('JSESSIONID'): + return True + return False + def __xml2py(self, obj): ''' Parse XML in to python entity diff --git a/src/ovirtsdk/web/connection.py b/src/ovirtsdk/web/connection.py index d17eebf..fa30fc4 100644 --- a/src/ovirtsdk/web/connection.py +++ b/src/ovirtsdk/web/connection.py @@ -54,16 +54,38 @@ def getConnection(self): return self.__connection - def getDefaultHeaders(self): + def getDefaultHeaders(self, no_auth=False): + ''' + Fetches headers to be used on request + + @param no_auth: do not authorize request (authorization is done via cookie) + ''' + + AUTH_HEADER = 'Authorization' + headers = self.__headers.copy() headers.update(self.__createDynamicHeaders()) + + # remove AUTH_HEADER + if no_auth and headers.has_key(AUTH_HEADER): + headers.pop(AUTH_HEADER) + return headers - def doRequest(self, method, url, body=urllib.urlencode({}), headers={}): - return self.__connection.request(method, url, body, self.getHeaders(headers)) + def doRequest(self, method, url, body=urllib.urlencode({}), headers={}, no_auth=False): + ''' + Performs HTTP request - def getHeaders(self, headers): - extended_headers = self.getDefaultHeaders() + @param method: HTTP method + @param url: URL to invoke the request on + @param body: request body + @param headers: request headers + @param no_auth: do not authorize request (authorization is done via cookie) + ''' + return self.__connection.request(method, url, body, self.getHeaders(headers, no_auth)) + + def getHeaders(self, headers, no_auth=False): + extended_headers = self.getDefaultHeaders(no_auth) for k in headers.keys(): if (headers[k] is None and extended_headers.has_key(k)): extended_headers.pop(k) @@ -72,6 +94,7 @@ extended_headers[k] = str(headers[k]) else: extended_headers[k] = headers[k] + return extended_headers def getResponse(self): -- To view, visit http://gerrit.ovirt.org/12578 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ief0ed86c26c2e74b8cc8f46d68b01f904c50d0e2 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine-sdk Gerrit-Branch: sdk_3.2 Gerrit-Owner: Michael Pasternak <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
