Browse Source

HUE-3649 [doc2] get_by_uuid should check permissions

Jenny Kim 9 năm trước cách đây
mục cha
commit
cf9fd23182

+ 1 - 1
apps/oozie/src/oozie/decorators.py

@@ -54,7 +54,7 @@ def check_document_access_permission():
         if doc_id is not None:
           doc2 = Document2.objects.get(id=doc_id)
         elif uuid is not None:
-          doc2 = Document2.objects.get_by_uuid(uuid)
+          doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=uuid)
 
         if doc2:
           doc2.doc.get().can_read_or_exception(request.user)

+ 3 - 1
apps/oozie/src/oozie/models2.py

@@ -2459,7 +2459,9 @@ class Coordinator(Job):
 
   @property
   def workflow(self):
-    wf_doc = Document2.objects.get_by_uuid(uuid=self.data['properties']['workflow'])
+    if self.document is None:
+      raise PopupException(_('Cannot return workflow since document attribute is None.'))
+    wf_doc = Document2.objects.get_by_uuid(user=self.document.owner, uuid=self.uuid)
     return Workflow(document=wf_doc)
 
   def get_absolute_url(self):

+ 2 - 2
apps/oozie/src/oozie/tests.py

@@ -3139,7 +3139,7 @@ class TestOozieSubmissions(OozieBase):
 
   def test_submit_hiveserver2_action(self):
     wf_uuid = "c1c3cba9-edec-fb6f-a526-9f80b66fe993"
-    wf = Document2.objects.get_by_uuid(uuid=wf_uuid)
+    wf = Document2.objects.get(uuid=wf_uuid)
     wf.data.replace('hive2://localhost:10000/default', _get_hiveserver2_url())
     wf.save()
 
@@ -3163,7 +3163,7 @@ class TestOozieSubmissions(OozieBase):
 
   def test_submit_spark_action(self):
     wf_uuid = "2d667ab2-70f9-c2bf-0726-abe84fa7130d"
-    wf = Document2.objects.get_by_uuid(uuid=wf_uuid)
+    wf = Document2.objects.get(uuid=wf_uuid)
 
     # Somewhere we delete those by mistake
     doc = Document.objects.link(wf, owner=wf.owner, name=wf.name, description=wf.description, extra='workflow2')

+ 3 - 3
apps/oozie/src/oozie/views/editor2.py

@@ -330,7 +330,7 @@ def action_parameters(request):
         elif node_data['type'] == 'pig':
           parameters = parameters.union(set(find_dollar_variables(data)))
     elif node_data['type'] == 'hive-document':
-      notebook = Notebook(document=Document2.objects.get_by_uuid(uuid=node_data['properties']['uuid']))
+      notebook = Notebook(document=Document2.objects.get_by_uuid(user=request.user, uuid=node_data['properties']['uuid']))
       parameters = parameters.union(set(find_dollar_braced_variables(notebook.get_str())))
 
     response['status'] = 0
@@ -655,7 +655,7 @@ def submit_coordinator(request, doc_id):
 
 def _submit_coordinator(request, coordinator, mapping):
   try:
-    wf_doc = Document2.objects.get_by_uuid(uuid=coordinator.data['properties']['workflow'])
+    wf_doc = Document2.objects.get_by_uuid(user=request.user, uuid=coordinator.data['properties']['workflow'])
     wf_dir = Submission(request.user, Workflow(document=wf_doc), request.fs, request.jt, mapping, local_tz=coordinator.data['properties']['timezone']).deploy()
 
     properties = {'wf_application_path': request.fs.get_hdfs_path(wf_dir)}
@@ -859,7 +859,7 @@ def schedule_document(request):
 
   uuid = request.POST.get('uuid')
 
-  document = Document2.objects.get_by_uuid(uuid=uuid)
+  document = Document2.objects.get_by_uuid(user=request.user, uuid=uuid)
   notebook = Notebook(document=document)
   parameters = find_dollar_braced_variables(notebook.get_str())
 

+ 1 - 1
apps/search/src/search/search_controller.py

@@ -84,7 +84,7 @@ class SearchController(object):
     try:
       for doc2 in self.get_shared_search_collections():
         if doc2.id in collection_ids:
-          doc2 = Document2.objects.get_by_uuid(uuid=doc2.uuid)
+          doc2 = Document2.objects.get_by_uuid(user=self.user, uuid=doc2.uuid)
           doc = doc2.doc.get()
 
           name = doc2.name + '-copy'

+ 17 - 23
desktop/core/src/desktop/api2.py

@@ -132,13 +132,10 @@ def get_document(request):
   with_dependencies = request.GET.get('dependencies', 'false').lower() == 'true'
 
   if uuid:
-    document = Document2.objects.get_by_uuid(uuid)
+    document = Document2.objects.get_by_uuid(user=request.user, uuid=uuid)
   else:  # Find by path
     document = Document2.objects.get_by_path(user=request.user, path=path)
 
-  # Check if user has read permissions
-  document.can_read_or_exception(request.user)
-
   response = {
     'document': document.to_dict(),
     'parent': document.parent_directory.to_dict() if document.parent_directory else None,
@@ -187,12 +184,8 @@ def move_document(request):
   if not source_doc_uuid or not destination_doc_uuid:
     raise PopupException(_('move_document requires source_doc_uuid and destination_doc_uuid'))
 
-  source = Document2.objects.get_by_uuid(uuid=source_doc_uuid)
-  destination = Directory.objects.get_by_uuid(uuid=destination_doc_uuid)
-
-  # Check if user has write permissions for both source and destination
-  source.can_write_or_exception(request.user)
-  destination.can_write_or_exception(request.user)
+  source = Document2.objects.get_by_uuid(user=request.user, uuid=source_doc_uuid, perm_type='write')
+  destination = Directory.objects.get_by_uuid(user=request.user, uuid=destination_doc_uuid, perm_type='write')
 
   doc = source.move(destination, request.user)
 
@@ -211,10 +204,7 @@ def create_directory(request):
   if not parent_uuid or not name:
     raise PopupException(_('create_directory requires parent_uuid and name'))
 
-  parent_dir = Directory.objects.get_by_uuid(uuid=parent_uuid)
-
-  # Check if user has write permissions for parent directory
-  parent_dir.can_write_or_exception(request.user)
+  parent_dir = Directory.objects.get_by_uuid(user=request.user, uuid=parent_uuid, perm_type='write')
 
   directory = Directory.objects.create(name=name, owner=request.user, parent_directory=parent_dir)
 
@@ -232,8 +222,7 @@ def update_document(request):
   if not uuid:
     raise PopupException(_('update_document requires uuid'))
 
-  document = Document2.objects.get_by_uuid(uuid=uuid)
-  document.can_write_or_exception(request.user)
+  document = Document2.objects.get_by_uuid(user=request.user, uuid=uuid, perm_type='write')
 
   whitelisted_attrs = ['name', 'description']
 
@@ -268,10 +257,7 @@ def delete_document(request):
   if not uuid:
     raise PopupException(_('delete_document requires uuid'))
 
-  document = Document2.objects.get_by_uuid(uuid=uuid)
-
-  # Check if user has write permissions for given document
-  document.can_write_or_exception(request.user)
+  document = Document2.objects.get_by_uuid(user=request.user, uuid=uuid, perm_type='write')
 
   if skip_trash:
     document.delete()
@@ -297,7 +283,7 @@ def share_document(request):
   if not uuid or not perms_dict:
     raise PopupException(_('share_document requires uuid and perms_dict'))
 
-  doc = Document2.objects.get_by_uuid(uuid=uuid)
+  doc = Document2.objects.get_by_uuid(user=request.user, uuid=uuid)
 
   for name, perm in perms_dict.iteritems():
     users = groups = None
@@ -476,11 +462,19 @@ def _copy_document_with_owner(doc, owner, uuids_map):
 
 def _create_or_update_document_with_owner(doc, owner, uuids_map):
   home_dir = Directory.objects.get_home_directory(owner)
+  create_new = False
 
   try:
-    existing_doc = Document2.objects.get_by_uuid(doc['fields']['uuid'], owner=owner)
-    doc['pk'] = existing_doc.pk
+    owned_docs = Document2.objects.filter(uuid=doc['fields']['uuid'], owner=owner).order_by('-last_modified')
+    if owned_docs.exists():
+      existing_doc = owned_docs[0]
+      doc['pk'] = existing_doc.pk
+    else:
+      create_new = True
   except FilesystemException, e:
+    create_new = True
+
+  if create_new:
     LOG.warn('Could not find document with UUID: %s, will create a new document on import.', doc['fields']['uuid'])
     doc['pk'] = None
     doc['fields']['version'] = 1

+ 14 - 13
desktop/core/src/desktop/models.py

@@ -892,29 +892,28 @@ class Document2Manager(models.Manager, Document2QueryMixin):
   def get_by_natural_key(self, uuid, version, is_history):
     return self.get(uuid=uuid, version=version, is_history=is_history)
 
-  def get_by_uuid(self, uuid, owner=None):
+  def get_by_uuid(self, user, uuid, perm_type='read'):
     """
     Since UUID is not a unique field, but part of a composite unique key, this returns the latest version by UUID
     This should always be used in place of Document2.objects.get(uuid=) when a single document is expected
-    WARNING: This does not check for read/write permissions!
 
+    :param user: User to check permissions against
     :param uuid
-    :param owner: optional filter
+    :param perm_type: permission type to check against
     """
-    docs = self.filter(uuid=uuid)
+    docs = self.filter(uuid=uuid).order_by('-last_modified')
 
-    if owner:
-      docs = docs.filter(owner=owner)
+    if not docs.exists():
+      raise FilesystemException(_('Document with UUID %s not found.') % uuid)
 
-    docs = docs.order_by('-last_modified')
+    latest_doc = docs[0]
 
-    if not docs.exists():
-      clause = ''
-      if owner:
-        clause = _(' and owner %s ') % owner.username
-      raise FilesystemException(_('Document with UUID %(uuid)s%(clause)s not found.') % {'uuid': uuid, 'clause': clause})
+    if perm_type == 'write':
+      latest_doc.can_write_or_exception(user)
+    else:
+      latest_doc.can_read_or_exception(user)
 
-    return docs[0]
+    return latest_doc
 
   def get_history(self, user, doc_type):
     return self.documents(user, perms='owned', include_history=True).filter(type=doc_type, is_history=True)
@@ -942,6 +941,8 @@ class Document2Manager(models.Manager, Document2QueryMixin):
         except Document2.MultipleObjectsReturned:
           raise FilesystemException(_('Duplicate documents found for user %s at path: %s') % (user.username, path))
 
+    doc.can_read_or_exception(user)
+
     return doc
 
   def create_user_directories(self, user):

+ 2 - 2
desktop/libs/liboozie/src/liboozie/submission2.py

@@ -178,7 +178,7 @@ class Submission(object):
         # Don't support more than one level sub-workflow
         if action.data['type'] == 'subworkflow':
           from oozie.models2 import Workflow
-          workflow = Workflow(document=Document2.objects.get_by_uuid(uuid=action.data['properties']['workflow']))
+          workflow = Workflow(document=Document2.objects.get_by_uuid(user=self.user, uuid=action.data['properties']['workflow']))
           sub_deploy = Submission(self.user, workflow, self.fs, self.jt, self.properties)
           workspace = sub_deploy.deploy()
 
@@ -186,7 +186,7 @@ class Submission(object):
           self.properties['workspace_%s' % workflow.uuid] = workspace # For pointing to the correct workspace
         elif action.data['type'] == 'hive-document':
           from notebook.models import Notebook
-          notebook = Notebook(document=Document2.objects.get_by_uuid(uuid=action.data['properties']['uuid']))
+          notebook = Notebook(document=Document2.objects.get_by_uuid(user=self.user, uuid=action.data['properties']['uuid']))
 
           self._create_file(deployment_dir, action.data['name'] + '.sql', notebook.get_str())
           #self.data['properties']['script_path'] = _generate_hive_script(self.data['uuid']) #'workspace_%s' % workflow.uui

+ 1 - 1
desktop/libs/notebook/src/notebook/api.py

@@ -242,7 +242,7 @@ def save_notebook(request):
   parent_uuid = notebook.get('parent_uuid', None)
   parent_directory = Document2.objects.get_home_directory(request.user)
   if parent_uuid:
-    parent_directory = Document2.objects.get_by_uuid(parent_uuid)
+    parent = Document2.objects.get_by_uuid(user=request.user, uuid=parent_uuid, perm_type='write')
 
   if notebook.get('parentUuid'):
     notebook_doc = Document2.objects.get(uuid=notebook['parentUuid'])

+ 2 - 2
desktop/libs/notebook/src/notebook/views.py

@@ -168,7 +168,7 @@ def delete(request):
   notebooks = json.loads(request.POST.get('notebooks', '[]'))
 
   for notebook in notebooks:
-    doc2 = Document2.objects.get_by_uuid(uuid=notebook['uuid'])
+    doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'], perm_type='write')
     doc = doc2.doc.get()
     doc.can_write_or_exception(request.user)
 
@@ -183,7 +183,7 @@ def copy(request):
   notebooks = json.loads(request.POST.get('notebooks', '[]'))
 
   for notebook in notebooks:
-    doc2 = Document2.objects.get_by_uuid(uuid=notebook['uuid'])
+    doc2 = Document2.objects.get_by_uuid(user=request.user, uuid=notebook['uuid'])
     doc = doc2.doc.get()
 
     name = doc2.name + '-copy'