Browse Source

Pass CSRF token as header in thrift calls (#3359)

Co-authored-by: Athithyaa Selvam <aselvam@cloudera.com>
Athithyaa Selvam 2 years ago
parent
commit
6e4c5f3d90

+ 23 - 0
apps/beeswax/gen-py/TCLIService/TCLIService.py

@@ -237,6 +237,28 @@ def add_xff_header(func):
     return func(*args, **kwargs)
     return func(*args, **kwargs)
   return wraps(func)(decorate)
   return wraps(func)(decorate)
 
 
+def add_csrf_header(func):
+  def decorate(*args, **kwargs):
+    self = args[0]
+    csrf = None
+    configuration = None
+    if args[1].__dict__ is not None and 'configuration' in args[1].__dict__:
+      configuration = args[1].__dict__['configuration']
+    if configuration is not None and 'X-CSRF-TOKEN' in configuration:
+        csrf = configuration.get('X-CSRF-TOKEN')
+    try:
+        if hasattr(self._oprot.trans, 'TFramedTransport'):
+          trans_client = self._oprot.trans._TFramedTransport__trans
+        else:
+          trans_client = self._oprot.trans._TBufferedTransport__trans
+
+        trans_client.setCustomHeaders({'X-CSRF-TOKEN': csrf})
+    except AttributeError as e:
+        LOG.error('Could not set CSRF header: %s' % smart_str(e))
+
+    return func(*args, **kwargs)
+  return wraps(func)(decorate)
+
 class Client(Iface):
 class Client(Iface):
     def __init__(self, iprot, oprot=None):
     def __init__(self, iprot, oprot=None):
         self._iprot = self._oprot = iprot
         self._iprot = self._oprot = iprot
@@ -244,6 +266,7 @@ class Client(Iface):
             self._oprot = oprot
             self._oprot = oprot
         self._seqid = 0
         self._seqid = 0
 
 
+    @add_csrf_header
     @add_xff_header
     @add_xff_header
     def OpenSession(self, req):
     def OpenSession(self, req):
         """
         """

+ 7 - 1
apps/beeswax/src/beeswax/server/hive_server2_lib.py

@@ -30,7 +30,7 @@ from TCLIService.ttypes import TOpenSessionReq, TGetTablesReq, TFetchResultsReq,
   TGetCrossReferenceReq, TGetPrimaryKeysReq
   TGetCrossReferenceReq, TGetPrimaryKeysReq
 
 
 from desktop.lib import python_util, thrift_util
 from desktop.lib import python_util, thrift_util
-from desktop.conf import DEFAULT_USER, USE_THRIFT_HTTP_JWT, ENABLE_XFF_FOR_HIVE_IMPALA
+from desktop.conf import DEFAULT_USER, USE_THRIFT_HTTP_JWT, ENABLE_XFF_FOR_HIVE_IMPALA, ENABLE_X_CSRF_TOKEN_FOR_HIVE_IMPALA
 
 
 from beeswax import conf as beeswax_conf, hive_site
 from beeswax import conf as beeswax_conf, hive_site
 from beeswax.hive_site import hiveserver2_use_ssl
 from beeswax.hive_site import hiveserver2_use_ssl
@@ -680,6 +680,9 @@ class HiveServerClient(object):
       xff_header = json.loads(user.userprofile.json_data).get('X-Forwarded-For', None)
       xff_header = json.loads(user.userprofile.json_data).get('X-Forwarded-For', None)
       if xff_header and ENABLE_XFF_FOR_HIVE_IMPALA.get():
       if xff_header and ENABLE_XFF_FOR_HIVE_IMPALA.get():
         kwargs['configuration'].update({'X-Forwarded-For': xff_header})
         kwargs['configuration'].update({'X-Forwarded-For': xff_header})
+      csrf_header = json.loads(user.userprofile.json_data).get('X-CSRF-TOKEN')
+      if csrf_header and ENABLE_X_CSRF_TOKEN_FOR_HIVE_IMPALA.get():
+        kwargs['configuration'].update({'X-CSRF-TOKEN': csrf_header})
 
 
     if self.query_server['server_name'] == 'hplsql' or interpreter['dialect'] == 'hplsql': # All the time
     if self.query_server['server_name'] == 'hplsql' or interpreter['dialect'] == 'hplsql': # All the time
       kwargs['configuration'].update({'hive.server2.proxy.user': user.username, 'set:hivevar:mode': 'HPLSQL'})
       kwargs['configuration'].update({'hive.server2.proxy.user': user.username, 'set:hivevar:mode': 'HPLSQL'})
@@ -695,6 +698,9 @@ class HiveServerClient(object):
       xff_header = json.loads(user.userprofile.json_data).get('X-Forwarded-For', None)
       xff_header = json.loads(user.userprofile.json_data).get('X-Forwarded-For', None)
       if xff_header and ENABLE_XFF_FOR_HIVE_IMPALA.get():
       if xff_header and ENABLE_XFF_FOR_HIVE_IMPALA.get():
         kwargs['configuration'].update({'X-Forwarded-For': xff_header})
         kwargs['configuration'].update({'X-Forwarded-For': xff_header})
+      csrf_header = json.loads(user.userprofile.json_data).get('X-CSRF-TOKEN', None)
+      if csrf_header and ENABLE_X_CSRF_TOKEN_FOR_HIVE_IMPALA.get():
+        kwargs['configuration'].update({'X-CSRF-TOKEN': csrf_header})
 
 
     LOG.info('Opening %s thrift session for user %s' % (self.query_server['server_name'], user.username))
     LOG.info('Opening %s thrift session for user %s' % (self.query_server['server_name'], user.username))
 
 

+ 3 - 0
desktop/conf.dist/hue.ini

@@ -189,6 +189,9 @@ http_500_debug_mode=false
 # Enable X-Forwarded-For header if hive/impala requires it.
 # Enable X-Forwarded-For header if hive/impala requires it.
 ## enable_xff_for_hive_impala=true
 ## enable_xff_for_hive_impala=true
 
 
+# Enable X-CSRF-Token header if hive/impala requries it
+## enable_x_csrf_token_for_hive_impala=true
+
 # Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER.
 # Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER.
 ## secure_proxy_ssl_header=false
 ## secure_proxy_ssl_header=false
 
 

+ 3 - 0
desktop/conf/pseudo-distributed.ini.tmpl

@@ -194,6 +194,9 @@
   # Enable X-Forwarded-For header if hive/impala requires it.
   # Enable X-Forwarded-For header if hive/impala requires it.
   ## enable_xff_for_hive_impala=true
   ## enable_xff_for_hive_impala=true
 
 
+  # Enable X-CSRF-Token header if hive/impala requires it.
+  ## enable_x_csrf_token_for_hive_impala=true
+
   # Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER.
   # Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER.
   ## secure_proxy_ssl_header=false
   ## secure_proxy_ssl_header=false
 
 

+ 5 - 0
desktop/core/src/desktop/auth/backend.py

@@ -245,6 +245,11 @@ def knox_login_headers(request):
     userprofile.save()
     userprofile.save()
   except Exception:
   except Exception:
     LOG.error("X-FORWARDED-FOR header not found")
     LOG.error("X-FORWARDED-FOR header not found")
+  try:
+    userprofile.update_data({'X-CSRF-TOKEN': request.META['CSRF_COOKIE']})
+    userprofile.save()
+  except:
+    LOG.error("X-CSRF-TOKEN header not found")
 
 
 class DesktopBackendBase(object):
 class DesktopBackendBase(object):
   """
   """

+ 5 - 1
desktop/core/src/desktop/auth/views.py

@@ -167,7 +167,11 @@ def dt_login(request, from_modal=False):
         try:
         try:
           userprofile.update_data({'X-Forwarded-For': request.META['HTTP_X_FORWARDED_FOR']})
           userprofile.update_data({'X-Forwarded-For': request.META['HTTP_X_FORWARDED_FOR']})
         except KeyError as e:
         except KeyError as e:
-          LOG.error('HTTP-X-FORWARDED-FOR header not found: %s' %smart_str(e))
+          LOG.error('HTTP-X-FORWARDED-FOR header not found: %s' % smart_str(e))
+        try:
+          userprofile.update_data({'X-CSRF-TOKEN': request.META['CSRF_COOKIE']})
+        except KeyError as e:
+          LOG.error('X-CSRF-TOKEN header not found: %s' % smart_str(e))
         userprofile.save()
         userprofile.save()
 
 
         msg = 'Successful login for user: %s' % user.username
         msg = 'Successful login for user: %s' % user.username

+ 6 - 0
desktop/core/src/desktop/conf.py

@@ -550,6 +550,12 @@ ENABLE_XFF_FOR_HIVE_IMPALA = Config(
   type=coerce_bool,
   type=coerce_bool,
   default=False)
   default=False)
 
 
+ENABLE_X_CSRF_TOKEN_FOR_HIVE_IMPALA = Config(
+  key="enable_x_csrf_token_for_hive_impala",
+  help=_("Enable X_CSRF_TOKEN header if the hive/impala requires it."),
+  type=coerce_bool,
+  default=False)
+
 SECURE_PROXY_SSL_HEADER = Config(
 SECURE_PROXY_SSL_HEADER = Config(
   key="secure_proxy_ssl_header",
   key="secure_proxy_ssl_header",
   help=_("Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER."),
   help=_("Support for HTTPS termination at the load-balancer level with SECURE_PROXY_SSL_HEADER."),

+ 4 - 1
desktop/core/src/desktop/lib/thrift_/http_client.py

@@ -80,7 +80,10 @@ class THttpClient(TTransportBase):
     self._headers.update(timeout=str(int(ms / 1000)))
     self._headers.update(timeout=str(int(ms / 1000)))
 
 
   def setCustomHeaders(self, headers):
   def setCustomHeaders(self, headers):
-    self._headers = headers
+    if self._headers:
+      self._headers.update(headers)
+    else:
+      self._headers = headers
 
 
   def read(self, sz):
   def read(self, sz):
     return self._data
     return self._data

+ 5 - 0
desktop/core/src/desktop/views.py

@@ -121,6 +121,11 @@ def saml_login_headers(request):
     userprofile.save()
     userprofile.save()
   except KeyError as e:
   except KeyError as e:
     LOG.error('X-FORWARDED-FOR header not found: %s' % smart_str(e))
     LOG.error('X-FORWARDED-FOR header not found: %s' % smart_str(e))
+  try:
+    userprofile.update_data({'X-CSRF-TOKEN': request.META['CSRF_COOKIE']})
+    userprofile.save()
+  except:
+    LOG.error("X-CSRF-TOKEN header not found")
 
 
 def hue(request):
 def hue(request):
   current_app, other_apps, apps_list = _get_apps(request.user, '')
   current_app, other_apps, apps_list = _get_apps(request.user, '')