Skip to content

Commit 17e2d4c

Browse files
first draft
1 parent 1e8559e commit 17e2d4c

File tree

4 files changed

+141
-19
lines changed

4 files changed

+141
-19
lines changed

zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ public void onMessage(NotebookSocket conn, String msg) {
168168
unicastNoteList(conn, subject);
169169
break;
170170
case RELOAD_NOTES_FROM_REPO:
171-
broadcastReloadedNoteList(subject);
171+
//broadcastReloadedNoteList(subject);
172+
unicastNoteList(conn, subject);
172173
break;
173174
case GET_HOME_NOTE:
174175
sendHomeNote(conn, userAndRoles, notebook, messagereceived);
@@ -331,7 +332,9 @@ private String getOpenNoteId(NotebookSocket socket) {
331332
private void broadcastToNoteBindedInterpreter(String interpreterGroupId,
332333
Message m) {
333334
Notebook notebook = notebook();
334-
List<Note> notes = notebook.getAllNotes();
335+
//TODO(khalid): anonymous or specific user notes?
336+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
337+
List<Note> notes = notebook.getAllNotes(subject);
335338
for (Note note : notes) {
336339
List<String> ids = notebook.getInterpreterFactory().getInterpreters(note.getId());
337340
for (String id : ids) {
@@ -472,6 +475,7 @@ public List<Map<String, String>> generateNotebooksInfo(boolean needsReload,
472475
LOG.error("Fail to reload notes from repository", e);
473476
}
474477
}
478+
475479
List<Note> notes = notebook.getAllNotes(subject);
476480
List<Map<String, String>> notesInfo = new LinkedList<>();
477481
for (Note note : notes) {
@@ -855,7 +859,9 @@ private void angularObjectUpdated(NotebookSocket conn, HashSet<String> userAndRo
855859

856860
if (global) { // broadcast change to all web session that uses related
857861
// interpreter.
858-
for (Note n : notebook.getAllNotes()) {
862+
//TODO(khalid): anonymous or specific user notes?
863+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
864+
for (Note n : notebook.getAllNotes(subject)) {
859865
List<InterpreterSetting> settings = notebook.getInterpreterFactory()
860866
.getInterpreterSettings(note.getId());
861867
for (InterpreterSetting setting : settings) {
@@ -1533,7 +1539,9 @@ public void onUpdate(String interpreterGroupId, AngularObject object) {
15331539
return;
15341540
}
15351541

1536-
List<Note> notes = notebook.getAllNotes();
1542+
//TODO(khalid): anonymous or specific user notes?
1543+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
1544+
List<Note> notes = notebook.getAllNotes(subject );
15371545
for (Note note : notes) {
15381546
if (object.getNoteId() != null && !note.getId().equals(object.getNoteId())) {
15391547
continue;
@@ -1558,7 +1566,9 @@ public void onUpdate(String interpreterGroupId, AngularObject object) {
15581566
@Override
15591567
public void onRemove(String interpreterGroupId, String name, String noteId, String paragraphId) {
15601568
Notebook notebook = notebook();
1561-
List<Note> notes = notebook.getAllNotes();
1569+
//TODO(khalid): anonymous or specific user notes?
1570+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
1571+
List<Note> notes = notebook.getAllNotes(subject);
15621572
for (Note note : notes) {
15631573
if (noteId != null && !note.getId().equals(noteId)) {
15641574
continue;

zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.zeppelin.notebook.Paragraph;
3333
import org.apache.zeppelin.scheduler.Job.Status;
3434
import org.apache.zeppelin.server.ZeppelinServer;
35+
import org.apache.zeppelin.user.AuthenticationInfo;
3536
import org.junit.AfterClass;
3637
import org.junit.BeforeClass;
3738
import org.junit.FixMethodOrder;
@@ -341,7 +342,9 @@ public void testListNotebooks() throws IOException {
341342
Map<String, Object> resp = gson.fromJson(get.getResponseBodyAsString(), new TypeToken<Map<String, Object>>() {
342343
}.getType());
343344
List<Map<String, String>> body = (List<Map<String, String>>) resp.get("body");
344-
assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes().size(), body.size());
345+
//TODO(khalid): anonymous or specific user notes?
346+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
347+
assertEquals("List notebooks are equal", ZeppelinServer.notebook.getAllNotes(subject).size(), body.size());
345348
get.releaseConnection();
346349
}
347350

zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Notebook.java

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.IOException;
2121
import java.io.StringReader;
2222
import java.util.ArrayList;
23+
import java.util.Arrays;
2324
import java.util.Collections;
2425
import java.util.Comparator;
2526
import java.util.Date;
@@ -31,9 +32,9 @@
3132
import java.util.Map;
3233
import java.util.Set;
3334
import java.util.concurrent.TimeUnit;
34-
3535
import com.google.common.base.Predicate;
3636
import com.google.common.collect.FluentIterable;
37+
import com.google.common.collect.Lists;
3738
import com.google.common.collect.Sets;
3839
import com.google.gson.Gson;
3940
import com.google.gson.GsonBuilder;
@@ -484,11 +485,74 @@ public void reloadAllNotes(AuthenticationInfo subject) throws IOException {
484485
}
485486

486487
List<NoteInfo> noteInfos = notebookRepo.list(subject);
488+
noteInfos = getAuthorizedNoteInfos(noteInfos, subject);
489+
487490
for (NoteInfo info : noteInfos) {
488491
loadNoteFromRepo(info.getId(), subject);
489492
}
490493
}
491494

495+
private List<NoteInfo> getAuthorizedNoteInfos(List<NoteInfo> notes, AuthenticationInfo subject) {
496+
Set<String> allIds = Sets.newHashSet();
497+
if (subject == null) {
498+
logger.warn("Subject for retrieving notes is null");
499+
return notes;
500+
}
501+
if ("anonymous".equals(subject.getUser())) {
502+
return notes;
503+
}
504+
for (NoteInfo note: notes) {
505+
allIds.add(note.getId());
506+
}
507+
Set<String> filteredIds = applyAuthorizationFilter(allIds, subject.getUser());
508+
List<NoteInfo> filteredNotes = Lists.newArrayList();
509+
for (NoteInfo note: notes) {
510+
if (filteredIds.contains(note.getId())){
511+
filteredNotes.add(note);
512+
}
513+
}
514+
return filteredNotes;
515+
}
516+
517+
//TODO(khalid): to change from processing everytime to keeping in memory view of each user
518+
public List<Note> getAuthorizedNotes(AuthenticationInfo subject) {
519+
List<Note> allNotes = new ArrayList<>(notes.values());
520+
Set<String> allIds = Sets.newHashSet();
521+
522+
if (subject == null) {
523+
logger.warn("Subject for retrieving notes is null");
524+
return allNotes;
525+
}
526+
if ("anonymous".equals(subject.getUser())) {
527+
return allNotes;
528+
}
529+
for (Note note: allNotes) {
530+
allIds.add(note.getId());
531+
}
532+
Set<String> filteredIds = applyAuthorizationFilter(allIds, subject.getUser());
533+
List<Note> filteredNotes = Lists.newArrayList();
534+
for (Note note: allNotes) {
535+
if (filteredIds.contains(note.getId())){
536+
filteredNotes.add(note);
537+
}
538+
}
539+
return filteredNotes;
540+
}
541+
542+
public Set<String> applyAuthorizationFilter(Set<String> ids, String user) {
543+
logger.info("applying filter for {}", user);
544+
Set<String> filteredIds = Sets.newHashSet();
545+
Set<String> userEntity = Sets.newHashSet((Arrays.asList(user)));
546+
NotebookAuthorization auth = getNotebookAuthorization();
547+
for (String id: ids) {
548+
if (auth.isOwner(id, userEntity) || auth.isReader(id, userEntity)
549+
|| auth.isWriter(id, userEntity)) {
550+
filteredIds.add(id);
551+
}
552+
}
553+
return filteredIds;
554+
}
555+
492556
private class SnapshotAngularObject {
493557
String intpGroupId;
494558
AngularObject angularObject;
@@ -514,9 +578,9 @@ Date getLastUpdate() {
514578
}
515579
}
516580

517-
public List<Note> getAllNotes() {
581+
public List<Note> getAllNotes(AuthenticationInfo subject) {
518582
synchronized (notes) {
519-
List<Note> noteList = new ArrayList<>(notes.values());
583+
List<Note> noteList = getAuthorizedNotes(subject);
520584
Collections.sort(noteList, new Comparator<Note>() {
521585
@Override
522586
public int compare(Note note1, Note note2) {
@@ -534,7 +598,7 @@ public int compare(Note note1, Note note2) {
534598
return noteList;
535599
}
536600
}
537-
601+
/*
538602
public List<Note> getAllNotes(AuthenticationInfo subject) {
539603
final Set<String> entities = Sets.newHashSet();
540604
if (subject != null) {
@@ -563,7 +627,7 @@ public int compare(Note note1, Note note2) {
563627
});
564628
}
565629
}
566-
630+
*/
567631
private Map<String, Object> getParagraphForJobManagerItem(Paragraph paragraph) {
568632
Map<String, Object> paragraphItem = new HashMap<>();
569633

@@ -696,7 +760,7 @@ public List<Map<String, Object>> getJobListByUnixTime(boolean needsReload,
696760
}
697761
}
698762

699-
List<Note> notes = getAllNotes();
763+
List<Note> notes = getAllNotes(subject);
700764
List<Map<String, Object>> notesInfo = new LinkedList<>();
701765
for (Note note : notes) {
702766
boolean isNotebookRunning = false;

zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,15 @@ public void testReloadAndSetInterpreter() throws IOException {
135135
File destDir = new File(notebookDir.getAbsolutePath() + "/2A94M5J1Z");
136136
FileUtils.copyDirectory(srcDir, destDir);
137137

138+
//TODO(khalid): anonymous or specific user notes?
139+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
140+
138141
// when load
139142
notebook.reloadAllNotes(null);
140-
assertEquals(1, notebook.getAllNotes().size());
143+
assertEquals(1, notebook.getAllNotes(subject).size());
141144

142145
// then interpreter factory should be injected into all the paragraphs
143-
Note note = notebook.getAllNotes().get(0);
146+
Note note = notebook.getAllNotes(subject).get(0);
144147
assertNull(note.getParagraphs().get(0).getRepl(null));
145148
}
146149

@@ -163,14 +166,17 @@ public void testReloadAllNotes() throws IOException {
163166
logger.error(e.toString(), e);
164167
}
165168

169+
//TODO(khalid): anonymous or specific user notes?
170+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
171+
166172
// doesn't have copied notebook in memory before reloading
167-
List<Note> notes = notebook.getAllNotes();
173+
List<Note> notes = notebook.getAllNotes(subject);
168174
assertEquals(notes.size(), 0);
169175

170176
// load copied notebook on memory when reloadAllNotes() is called
171177
Note copiedNote = notebookRepo.get("2A94M5J1Z", null);
172178
notebook.reloadAllNotes(null);
173-
notes = notebook.getAllNotes();
179+
notes = notebook.getAllNotes(subject);
174180
assertEquals(notes.size(), 2);
175181
assertEquals(notes.get(1).getId(), copiedNote.getId());
176182
assertEquals(notes.get(1).getName(), copiedNote.getName());
@@ -183,15 +189,52 @@ public void testReloadAllNotes() throws IOException {
183189
}
184190

185191
// keep notebook in memory before reloading
186-
notes = notebook.getAllNotes();
192+
notes = notebook.getAllNotes(subject);
187193
assertEquals(notes.size(), 2);
188194

189195
// delete notebook from notebook list when reloadAllNotes() is called
190196
notebook.reloadAllNotes(null);
191-
notes = notebook.getAllNotes();
197+
notes = notebook.getAllNotes(subject);
192198
assertEquals(notes.size(), 0);
193199
}
194200

201+
@Test
202+
public void testReloadAuthorizedNotes() throws IOException {
203+
AuthenticationInfo user1 = new AuthenticationInfo("user1");
204+
AuthenticationInfo user2 = new AuthenticationInfo("user2");
205+
notebook.reloadAllNotes(user1);
206+
List<Note> notes1 = notebook.getAllNotes(user1);
207+
notebook.reloadAllNotes(user2);
208+
List<Note> notes2 = notebook.getAllNotes(user2);
209+
assertEquals(notes1.size(), 0);
210+
assertEquals(notes2.size(), 0);
211+
logger.info("Loaded {} notes", notes1.size());
212+
213+
Note note = notebook.createNote(user1);
214+
setNotePermissions(note.id(), user1.getUser(), true, true, true);
215+
notebook.reloadAllNotes(user1);
216+
notes1 = notebook.getAllNotes(user1);
217+
notebook.reloadAllNotes(user2);
218+
notes2 = notebook.getAllNotes(user2);
219+
assertEquals(notes1.size(), 1);
220+
assertEquals(notes2.size(), 0);
221+
}
222+
223+
//fails if all failed, otherwise true
224+
private boolean setNotePermissions(String noteId, String user, boolean isOwner, boolean isReader, boolean isWriter) {
225+
NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization();
226+
Set<String> owners = notebookAuthorization.getOwners(noteId);
227+
Set<String> readers = notebookAuthorization.getReaders(noteId);
228+
Set<String> writers = notebookAuthorization.getWriters(noteId);
229+
boolean ownerSet = isOwner ? owners.add(user) : owners.remove(user);
230+
boolean readerSet = isReader ? readers.add(user) : readers.remove(user);
231+
boolean writerSet = isWriter ? writers.add(user) : writers.remove(user);
232+
notebookAuthorization.setOwners(noteId, owners);
233+
notebookAuthorization.setReaders(noteId, readers);
234+
notebookAuthorization.setWriters(noteId, writers);
235+
return ownerSet || readerSet || writerSet;
236+
}
237+
195238
@Test
196239
public void testPersist() throws IOException, SchedulerException, RepositoryException {
197240
Note note = notebook.createNote(null);
@@ -207,7 +250,9 @@ public void testPersist() throws IOException, SchedulerException, RepositoryExce
207250
Notebook notebook2 = new Notebook(
208251
conf, notebookRepo, schedulerFactory,
209252
new InterpreterFactory(conf, null, null, null, depResolver), this, null, null, null);
210-
assertEquals(1, notebook2.getAllNotes().size());
253+
//TODO(khalid): anonymous or specific user notes?
254+
AuthenticationInfo subject = new AuthenticationInfo("anonymous");
255+
assertEquals(1, notebook2.getAllNotes(subject).size());
211256
}
212257

213258
@Test

0 commit comments

Comments
 (0)