Repository: incubator-zeppelin Updated Branches: refs/heads/master f0a7caa68 -> 2d85f3a95
[ZEPPELIN-705]Search should aware notebook permission ### What is this PR for? Make search aware of notebook permissions and allow only those search results for which user has read permission. ### What type of PR is it? Bug Fix ### Todos NA ### What is the Jira issue? [ZEPPELIN-705]( https://issues.apache.org/jira/browse/ZEPPELIN-705?jql=project%20%3D%20ZEPPELIN%20AND%20status%20in%20(Open%2C%20Resolved)%20AND%20resolution%20%3D%20Unresolved%20AND%20fixVersion%20%3D%200.6.0%20ORDER%20BY%20due%20ASC%2C%20priority%20DESC%2C%20created%20ASC) ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update?No * Is there breaking changes for older versions?No * Does this needs documentation?No Author: Ravi Ranjan <[email protected]> Closes #833 from ravicodder/ZEPPELIN-705 and squashes the following commits: a4a9999 [Ravi Ranjan] Make test more Readable c42573e [Ravi Ranjan] Add check to see search searching all allowed notebook 7a624d0 [Ravi Ranjan] Add rest API test 2fe33e5 [Ravi Ranjan] search should aware notebook permissions Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/2d85f3a9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/2d85f3a9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/2d85f3a9 Branch: refs/heads/master Commit: 2d85f3a9571c6fe59ffd1795c023adbe232ad511 Parents: f0a7caa Author: Ravi Ranjan <[email protected]> Authored: Tue Apr 26 10:57:37 2016 +0530 Committer: Alexander Bezzubov <[email protected]> Committed: Tue May 3 16:39:54 2016 +0900 ---------------------------------------------------------------------- .../apache/zeppelin/rest/NotebookRestApi.java | 19 +++++- .../zeppelin/rest/ZeppelinRestApiTest.java | 66 ++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/2d85f3a9/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java index 482ea78..89e84ee 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java @@ -665,14 +665,29 @@ public class NotebookRestApi { } /** - * Search for a Notes + * Search for a Notes with permissions */ @GET @Path("search") public Response search(@QueryParam("q") String queryTerm) { LOG.info("Searching notebooks for: {}", queryTerm); + String principal = SecurityUtils.getPrincipal(); + HashSet<String> roles = SecurityUtils.getRoles(); + HashSet<String> userAndRoles = new HashSet<String>(); + userAndRoles.add(principal); + userAndRoles.addAll(roles); List<Map<String, String>> notebooksFound = notebookIndex.query(queryTerm); - LOG.info("{} notbooks found", notebooksFound.size()); + for (int i = 0; i < notebooksFound.size(); i++) { + String[] Id = notebooksFound.get(i).get("id").split("/", 2); + String noteId = Id[0]; + if (!notebookAuthorization.isOwner(noteId, userAndRoles) && + !notebookAuthorization.isReader(noteId, userAndRoles) && + !notebookAuthorization.isWriter(noteId, userAndRoles)) { + notebooksFound.remove(i); + i--; + } + } + LOG.info("{} notebooks found", notebooksFound.size()); return new JsonResponse<>(Status.OK, notebooksFound).build(); } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/2d85f3a9/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java index 3c7c7d0..2f2a36b 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java @@ -18,6 +18,7 @@ package org.apache.zeppelin.rest; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -690,5 +691,70 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { ZeppelinServer.notebook.removeNote(note.getId()); } + + @Test + public void testSearch() throws IOException { + Map<String, String> body; + + GetMethod getSecurityTicket = httpGet("/security/ticket"); + getSecurityTicket.addRequestHeader("Origin", "http://localhost"); + Map<String, Object> respSecurityTicket = gson.fromJson(getSecurityTicket.getResponseBodyAsString(), + new TypeToken<Map<String, Object>>() { + }.getType()); + body = (Map<String, String>) respSecurityTicket.get("body"); + String username = body.get("principal"); + getSecurityTicket.releaseConnection(); + + Note note1 = ZeppelinServer.notebook.createNote(); + String jsonRequest = "{\"title\": \"title1\", \"text\": \"ThisIsToTestSearchMethodWithPermissions 1\"}"; + PostMethod postNotebookText = httpPost("/notebook/" + note1.getId() + "/paragraph", jsonRequest); + postNotebookText.releaseConnection(); + + Note note2 = ZeppelinServer.notebook.createNote(); + jsonRequest = "{\"title\": \"title1\", \"text\": \"ThisIsToTestSearchMethodWithPermissions 2\"}"; + postNotebookText = httpPost("/notebook/" + note2.getId() + "/paragraph", jsonRequest); + postNotebookText.releaseConnection(); + + String jsonPermissions = "{\"owners\":[\"" + username + "\"],\"readers\":[\"" + username + "\"],\"writers\":[\"" + username + "\"]}"; + PutMethod putPermission = httpPut("/notebook/" + note1.getId() + "/permissions", jsonPermissions); + putPermission.releaseConnection(); + + jsonPermissions = "{\"owners\":[\"admin\"],\"readers\":[\"admin\"],\"writers\":[\"admin\"]}"; + putPermission = httpPut("/notebook/" + note2.getId() + "/permissions", jsonPermissions); + putPermission.releaseConnection(); + + GetMethod searchNotebook = httpGet("/notebook/search?q='ThisIsToTestSearchMethodWithPermissions'"); + searchNotebook.addRequestHeader("Origin", "http://localhost"); + Map<String, Object> respSearchResult = gson.fromJson(searchNotebook.getResponseBodyAsString(), + new TypeToken<Map<String, Object>>() { + }.getType()); + ArrayList searchBody = (ArrayList) respSearchResult.get("body"); + + assertEquals("At-least one search results is there", true, searchBody.size() >= 1); + + for (int i = 0; i < searchBody.size(); i++) { + Map<String, String> searchResult = (Map<String, String>) searchBody.get(i); + String userId = searchResult.get("id").split("/", 2)[0]; + GetMethod getPermission = httpGet("/notebook/" + userId + "/permissions"); + getPermission.addRequestHeader("Origin", "http://localhost"); + Map<String, Object> resp = gson.fromJson(getPermission.getResponseBodyAsString(), + new TypeToken<Map<String, Object>>() { + }.getType()); + Map<String, ArrayList> permissions = (Map<String, ArrayList>) resp.get("body"); + ArrayList owners = permissions.get("owners"); + ArrayList readers = permissions.get("readers"); + ArrayList writers = permissions.get("writers"); + + if (owners.size() != 0 && readers.size() != 0 && writers.size() != 0) { + assertEquals("User has permissions ", true, (owners.contains(username) || readers.contains(username) || + writers.contains(username))); + } + getPermission.releaseConnection(); + } + searchNotebook.releaseConnection(); + ZeppelinServer.notebook.removeNote(note1.getId()); + ZeppelinServer.notebook.removeNote(note2.getId()); + } + }
