You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by zj...@apache.org on 2021/02/23 09:32:09 UTC

[zeppelin] branch master updated: [Security] Notebook permission bypass vulnerability

This is an automated email from the ASF dual-hosted git repository.

zjffdu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 409235e  [Security] Notebook permission bypass vulnerability
409235e is described below

commit 409235e8db2ac370eed22d73a67d0771e886f907
Author: Jeff Zhang <zj...@apache.org>
AuthorDate: Thu Feb 4 07:25:30 2021 +0800

    [Security] Notebook permission bypass vulnerability
---
 .../apache/zeppelin/user/AuthenticationInfo.java   |  34 ++-
 .../zeppelin/user/AuthenticationInfoTest.java      |  42 ---
 .../org/apache/zeppelin/rest/LoginRestApi.java     |   9 +-
 .../org/apache/zeppelin/rest/NotebookRestApi.java  |   2 +-
 .../org/apache/zeppelin/rest/SecurityRestApi.java  |  12 +-
 .../org/apache/zeppelin/socket/NotebookServer.java | 296 +++++++++++----------
 .../apache/zeppelin/socket/NotebookServerTest.java |  10 +-
 .../zeppelin/ticket/TicketContainerTest.java       |   8 +-
 .../zeppelinhub/websocket/ZeppelinhubClient.java   |   4 +-
 .../websocket/listener/WatcherWebsocket.java       |   2 +-
 .../apache/zeppelin/ticket/TicketContainer.java    |  55 +++-
 11 files changed, 260 insertions(+), 214 deletions(-)

diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/user/AuthenticationInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/user/AuthenticationInfo.java
index 1444025..a6c0e41 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/user/AuthenticationInfo.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/user/AuthenticationInfo.java
@@ -20,8 +20,11 @@ package org.apache.zeppelin.user;
 
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
+import com.google.common.collect.Sets;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.zeppelin.common.JsonSerializable;
 import org.slf4j.Logger;
@@ -34,13 +37,13 @@ import com.google.gson.Gson;
  */
 public class AuthenticationInfo implements JsonSerializable {
   private static final Logger LOG = LoggerFactory.getLogger(AuthenticationInfo.class);
-  private static final Gson gson = new Gson();
+  private static final Gson GSON = new Gson();
 
   String user;
-  List<String> roles;
+  Set<String> roles;
   String ticket;
   UserCredentials userCredentials;
-  public static final AuthenticationInfo ANONYMOUS = new AuthenticationInfo("anonymous", null,
+  public static final AuthenticationInfo ANONYMOUS = new AuthenticationInfo("anonymous", Sets.newHashSet(),
       "anonymous");
 
   public AuthenticationInfo() {}
@@ -54,10 +57,21 @@ public class AuthenticationInfo implements JsonSerializable {
    * @param user
    * @param ticket
    */
+  public AuthenticationInfo(String user, Set<String> roles, String ticket) {
+    this.user = user;
+    this.ticket = ticket;
+    this.roles = roles;
+  }
+
   public AuthenticationInfo(String user, String roles, String ticket) {
     this.user = user;
     this.ticket = ticket;
-    this.roles = gson.fromJson(roles, ArrayList.class);
+    List<String> rolesList = GSON.fromJson(roles, ArrayList.class);
+    if (roles == null) {
+      this.roles = new HashSet<>();
+    } else {
+      this.roles = new HashSet<>(rolesList);
+    }
   }
 
   public String getUser() {
@@ -68,18 +82,14 @@ public class AuthenticationInfo implements JsonSerializable {
     this.user = user;
   }
 
-  public List<String> getRoles() {
+  public Set<String> getRoles() {
     return roles;
   }
 
-  public void setRoles(List<String> roles) {
+  public void setRoles(Set<String> roles) {
     this.roles = roles;
   }
 
-  public void setRoles(String roles) {
-    this.roles = gson.fromJson(roles, ArrayList.class);
-  }
-
   public List<String> getUsersAndRoles() {
     List<String> usersAndRoles = new ArrayList<>();
     if (roles != null) {
@@ -124,10 +134,10 @@ public class AuthenticationInfo implements JsonSerializable {
 
   @Override
   public String toJson() {
-    return gson.toJson(this);
+    return GSON.toJson(this);
   }
 
   public static AuthenticationInfo fromJson(String json) {
-    return gson.fromJson(json, AuthenticationInfo.class);
+    return GSON.fromJson(json, AuthenticationInfo.class);
   }
 }
diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/user/AuthenticationInfoTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/user/AuthenticationInfoTest.java
deleted file mode 100644
index b757033..0000000
--- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/user/AuthenticationInfoTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.zeppelin.user;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.junit.Test;
-
-public class AuthenticationInfoTest {
-
-  @Test
-  public void testRoles() {
-    final String roles = "[\"role1\", \"role2\", \"role with space\"]";
-
-    final AuthenticationInfo authenticationInfo = new AuthenticationInfo("foo",
-        roles, "bar");
-
-    assertEquals(
-        new ArrayList<>(Arrays.asList("role1", "role2", "role with space")),
-        authenticationInfo.getRoles());
-
-  }
-
-}
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java
index a887e30..d42f10e 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java
@@ -192,12 +192,13 @@ public class LoginRestApi {
 
       Set<String> roles = authenticationService.getAssociatedRoles();
       String principal = authenticationService.getPrincipal();
-      String ticket = "anonymous".equals(principal) ? "anonymous" : TicketContainer.instance.getTicket(principal);
+      TicketContainer.Entry ticketEntry = "anonymous".equals(principal) ?
+              TicketContainer.ANONYMOUS_ENTRY : TicketContainer.instance.getTicketEntry(principal, roles);
 
       Map<String, String> data = new HashMap<>();
-      data.put("principal", principal);
-      data.put("roles", GSON.toJson(roles));
-      data.put("ticket", ticket);
+      data.put("principal", ticketEntry.getPrincipal());
+      data.put("roles", GSON.toJson(ticketEntry.getRoles()));
+      data.put("ticket", ticketEntry.getTicket());
 
       response = new JsonResponse<>(Status.OK, "", data);
       // if no exception, that's it, we're done!
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 11b0cf9..c5a3db4 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
@@ -731,7 +731,7 @@ public class NotebookRestApi extends AbstractRestApi {
     LOGGER.info("Run note jobs, noteId: {}, blocking: {}, isolated: {}, params: {}", noteId, blocking, isolated, params);
     Note note = notebook.getNote(noteId);
     AuthenticationInfo subject = new AuthenticationInfo(authenticationService.getPrincipal());
-    subject.setRoles(new LinkedList<>(authenticationService.getAssociatedRoles()));
+    subject.setRoles(authenticationService.getAssociatedRoles());
     checkIfNoteIsNotNull(note, noteId);
     checkIfUserCanRun(noteId, "Insufficient privileges you cannot run job for this note");
 
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
index 9d5a6fe..4d41477 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java
@@ -70,17 +70,17 @@ public class SecurityRestApi {
     String principal = authenticationService.getPrincipal();
     Set<String> roles = authenticationService.getAssociatedRoles();
     // ticket set to anonymous for anonymous user. Simplify testing.
-    String ticket;
+    TicketContainer.Entry ticketEntry;
     if ("anonymous".equals(principal)) {
-      ticket = "anonymous";
+      ticketEntry = TicketContainer.ANONYMOUS_ENTRY;
     } else {
-      ticket = TicketContainer.instance.getTicket(principal);
+      ticketEntry = TicketContainer.instance.getTicketEntry(principal, roles);
     }
 
     Map<String, String> data = new HashMap<>();
-    data.put("principal", principal);
-    data.put("roles", gson.toJson(roles));
-    data.put("ticket", ticket);
+    data.put("principal", ticketEntry.getPrincipal());
+    data.put("roles", gson.toJson(ticketEntry.getRoles()));
+    data.put("ticket", ticketEntry.getTicket());
 
     JsonResponse<Map<String, String>> response = new JsonResponse<>(Response.Status.OK, "", data);
     LOG.warn("{}", response);
diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
index 146e8e9..4938bd3 100644
--- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
+++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java
@@ -263,18 +263,18 @@ public class NotebookServer extends WebSocketServlet
         LOG.trace("RECEIVE MSG = " + messagereceived);
       }
 
-      String ticket = TicketContainer.instance.getTicket(messagereceived.principal);
-      if (ticket != null &&
-          (messagereceived.ticket == null || !ticket.equals(messagereceived.ticket))) {
+      TicketContainer.Entry ticketEntry = TicketContainer.instance.getTicketEntry(messagereceived.principal);
+      if (ticketEntry != null &&
+              (messagereceived.ticket == null || !ticketEntry.getTicket().equals(messagereceived.ticket))) {
         /* not to pollute logs, log instead of exception */
         if (StringUtils.isEmpty(messagereceived.ticket)) {
           LOG.debug("{} message: invalid ticket {} != {}", messagereceived.op,
-              messagereceived.ticket, ticket);
+                  messagereceived.ticket, ticketEntry.getTicket());
         } else {
           if (!messagereceived.op.equals(OP.PING)) {
             conn.send(serializeMessage(new Message(OP.SESSION_LOGOUT).put("info",
-                "Your ticket is invalid possibly due to server restart. "
-                    + "Please login again.")));
+                    "Your ticket is invalid possibly due to server restart. "
+                            + "Please login again.")));
           }
         }
         return;
@@ -299,108 +299,109 @@ public class NotebookServer extends WebSocketServlet
         getConnectionManager().addUserConnection(messagereceived.principal, conn);
       }
 
+      ServiceContext context = getServiceContext(ticketEntry);
       // Lets be elegant here
       switch (messagereceived.op) {
         case LIST_NOTES:
-          listNotesInfo(conn, messagereceived);
+          listNotesInfo(conn, context);
           break;
         case RELOAD_NOTES_FROM_REPO:
-          broadcastReloadedNoteList(conn, getServiceContext(messagereceived));
+          broadcastReloadedNoteList(conn, context);
           break;
         case GET_HOME_NOTE:
-          getHomeNote(conn, messagereceived);
+          getHomeNote(conn, context);
           break;
         case GET_NOTE:
-          getNote(conn, messagereceived);
+          getNote(conn, context, messagereceived);
           break;
         case NEW_NOTE:
-          createNote(conn, messagereceived);
+          createNote(conn, context, messagereceived);
           break;
         case DEL_NOTE:
-          deleteNote(conn, messagereceived);
+          deleteNote(conn, context, messagereceived);
           break;
         case REMOVE_FOLDER:
-          removeFolder(conn, messagereceived);
+          removeFolder(conn, context, messagereceived);
           break;
         case MOVE_NOTE_TO_TRASH:
-          moveNoteToTrash(conn, messagereceived);
+          moveNoteToTrash(conn, context, messagereceived);
           break;
         case MOVE_FOLDER_TO_TRASH:
-          moveFolderToTrash(conn, messagereceived);
+          moveFolderToTrash(conn, context, messagereceived);
           break;
         case EMPTY_TRASH:
-          emptyTrash(conn, messagereceived);
+          emptyTrash(conn, context);
           break;
         case RESTORE_FOLDER:
-          restoreFolder(conn, messagereceived);
+          restoreFolder(conn, context, messagereceived);
           break;
         case RESTORE_NOTE:
-          restoreNote(conn, messagereceived);
+          restoreNote(conn, context, messagereceived);
           break;
         case RESTORE_ALL:
-          restoreAll(conn, messagereceived);
+          restoreAll(conn, context, messagereceived);
           break;
         case CLONE_NOTE:
-          cloneNote(conn, messagereceived);
+          cloneNote(conn, context, messagereceived);
           break;
         case IMPORT_NOTE:
-          importNote(conn, messagereceived);
+          importNote(conn, context,  messagereceived);
           break;
         case CONVERT_NOTE_NBFORMAT:
           convertNote(conn, messagereceived);
           break;
         case COMMIT_PARAGRAPH:
-          updateParagraph(conn, messagereceived);
+          updateParagraph(conn, context, messagereceived);
           break;
         case RUN_PARAGRAPH:
-          runParagraph(conn, messagereceived);
+          runParagraph(conn, context, messagereceived);
           break;
         case PARAGRAPH_EXECUTED_BY_SPELL:
-          broadcastSpellExecution(conn, messagereceived);
+          broadcastSpellExecution(conn, context, messagereceived);
           break;
         case RUN_ALL_PARAGRAPHS:
-          runAllParagraphs(conn, messagereceived);
+          runAllParagraphs(conn, context, messagereceived);
           break;
         case CANCEL_PARAGRAPH:
-          cancelParagraph(conn, messagereceived);
+          cancelParagraph(conn, context, messagereceived);
           break;
         case MOVE_PARAGRAPH:
-          moveParagraph(conn, messagereceived);
+          moveParagraph(conn, context, messagereceived);
           break;
         case INSERT_PARAGRAPH:
-          insertParagraph(conn, messagereceived);
+          insertParagraph(conn, context, messagereceived);
           break;
         case COPY_PARAGRAPH:
-          copyParagraph(conn, messagereceived);
+          copyParagraph(conn, context, messagereceived);
           break;
         case PARAGRAPH_REMOVE:
-          removeParagraph(conn, messagereceived);
+          removeParagraph(conn, context, messagereceived);
           break;
         case PARAGRAPH_CLEAR_OUTPUT:
-          clearParagraphOutput(conn, messagereceived);
+          clearParagraphOutput(conn, context, messagereceived);
           break;
         case PARAGRAPH_CLEAR_ALL_OUTPUT:
-          clearAllParagraphOutput(conn, messagereceived);
+          clearAllParagraphOutput(conn, context, messagereceived);
           break;
         case NOTE_UPDATE:
-          updateNote(conn, messagereceived);
+          updateNote(conn, context, messagereceived);
           break;
         case NOTE_RENAME:
-          renameNote(conn, messagereceived);
+          renameNote(conn, context, messagereceived);
           break;
         case FOLDER_RENAME:
-          renameFolder(conn, messagereceived);
+          renameFolder(conn, context,messagereceived);
           break;
         case UPDATE_PERSONALIZED_MODE:
-          updatePersonalizedMode(conn, messagereceived);
+          updatePersonalizedMode(conn, context, messagereceived);
           break;
         case COMPLETION:
-          completion(conn, messagereceived);
+          completion(conn, context, messagereceived);
           break;
         case PING:
           break; //do nothing
         case ANGULAR_OBJECT_UPDATED:
-          angularObjectUpdated(conn, messagereceived);
+          angularObjectUpdated(conn, context, messagereceived);
           break;
         case ANGULAR_OBJECT_CLIENT_BIND:
           angularObjectClientBind(conn, messagereceived);
@@ -409,52 +410,52 @@ public class NotebookServer extends WebSocketServlet
           angularObjectClientUnbind(conn, messagereceived);
           break;
         case LIST_CONFIGURATIONS:
-          sendAllConfigurations(conn, messagereceived);
+          sendAllConfigurations(conn, context, messagereceived);
           break;
         case CHECKPOINT_NOTE:
-          checkpointNote(conn, messagereceived);
+          checkpointNote(conn, context, messagereceived);
           break;
         case LIST_REVISION_HISTORY:
-          listRevisionHistory(conn, messagereceived);
+          listRevisionHistory(conn, context, messagereceived);
           break;
         case SET_NOTE_REVISION:
-          setNoteRevision(conn, messagereceived);
+          setNoteRevision(conn, context, messagereceived);
           break;
         case NOTE_REVISION:
-          getNoteByRevision(conn, messagereceived);
+          getNoteByRevision(conn, context, messagereceived);
           break;
         case NOTE_REVISION_FOR_COMPARE:
-          getNoteByRevisionForCompare(conn, messagereceived);
+          getNoteByRevisionForCompare(conn, context, messagereceived);
           break;
         case LIST_NOTE_JOBS:
-          unicastNoteJobInfo(conn, messagereceived);
+          unicastNoteJobInfo(conn, context, messagereceived);
           break;
         case UNSUBSCRIBE_UPDATE_NOTE_JOBS:
           unsubscribeNoteJobInfo(conn);
           break;
         case GET_INTERPRETER_BINDINGS:
-          getInterpreterBindings(conn, messagereceived);
+          getInterpreterBindings(conn, context, messagereceived);
           break;
         case SAVE_INTERPRETER_BINDINGS:
-          saveInterpreterBindings(conn, messagereceived);
+          saveInterpreterBindings(conn, context, messagereceived);
           break;
         case EDITOR_SETTING:
-          getEditorSetting(conn, messagereceived);
+          getEditorSetting(conn, context, messagereceived);
           break;
         case GET_INTERPRETER_SETTINGS:
-          getInterpreterSettings(conn, messagereceived);
+          getInterpreterSettings(conn, context, messagereceived);
           break;
         case WATCHER:
           getConnectionManager().switchConnectionToWatcher(conn);
           break;
         case SAVE_NOTE_FORMS:
-          saveNoteForms(conn, messagereceived);
+          saveNoteForms(conn, context, messagereceived);
           break;
         case REMOVE_NOTE_FORMS:
-          removeNoteForms(conn, messagereceived);
+          removeNoteForms(conn, context, messagereceived);
           break;
         case PATCH_PARAGRAPH:
-          patchParagraph(conn, messagereceived);
+          patchParagraph(conn, context, messagereceived);
           break;
         default:
           break;
@@ -489,10 +490,12 @@ public class NotebookServer extends WebSocketServlet
     getConnectionManager().broadcast(m);
   }
 
-  public void unicastNoteJobInfo(NotebookSocket conn, Message fromMessage) throws IOException {
+  public void unicastNoteJobInfo(NotebookSocket conn,
+                                 ServiceContext context,
+                                 Message fromMessage) throws IOException {
 
     getConnectionManager().addNoteConnection(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(), conn);
-    getJobManagerService().getNoteJobInfoByUnixTime(0, getServiceContext(fromMessage),
+    getJobManagerService().getNoteJobInfoByUnixTime(0, context,
         new WebSocketServiceCallback<List<JobManagerService.NoteJobInfo>>(conn) {
           @Override
           public void onSuccess(List<JobManagerService.NoteJobInfo> notesJobInfo,
@@ -538,9 +541,10 @@ public class NotebookServer extends WebSocketServlet
     getConnectionManager().removeNoteConnection(JobManagerServiceType.JOB_MANAGER_PAGE.getKey(), conn);
   }
 
-  public void getInterpreterBindings(NotebookSocket conn, Message fromMessage) throws IOException {
+  public void getInterpreterBindings(NotebookSocket conn,
+                                     ServiceContext context,
+                                     Message fromMessage) throws IOException {
     List<InterpreterSettingsList> settingList = new ArrayList<>();
-    ServiceContext context = getServiceContext(fromMessage);
     String noteId = (String) fromMessage.data.get("noteId");
     Note note = getNotebook().getNote(noteId);
     if (note != null) {
@@ -555,10 +559,9 @@ public class NotebookServer extends WebSocketServlet
         new Message(OP.INTERPRETER_BINDINGS).put("interpreterBindings", settingList)));
   }
 
-  public void saveInterpreterBindings(NotebookSocket conn, Message fromMessage) throws IOException {
+  public void saveInterpreterBindings(NotebookSocket conn, ServiceContext context, Message fromMessage) throws IOException {
     List<InterpreterSettingsList> settingList = new ArrayList<>();
     String noteId = (String) fromMessage.data.get("noteId");
-    ServiceContext context = getServiceContext(fromMessage);
     Note note = getNotebook().getNote(noteId);
     if (note != null) {
       List<String> settingIdList =
@@ -566,8 +569,7 @@ public class NotebookServer extends WebSocketServlet
                       new TypeToken<ArrayList<String>>() {}.getType());
       if (!settingIdList.isEmpty()) {
         note.setDefaultInterpreterGroup(settingIdList.get(0));
-        getNotebook().saveNote(note,
-                new AuthenticationInfo(fromMessage.principal, fromMessage.roles, fromMessage.ticket));
+        getNotebook().saveNote(note, context.getAutheInfo());
       }
       List<InterpreterSetting> bindedSettings =
               note.getBindedInterpreterSettings(new ArrayList<>(context.getUserAndRoles()));
@@ -766,8 +768,8 @@ public class NotebookServer extends WebSocketServlet
     }
   }
 
-  public void listNotesInfo(NotebookSocket conn, Message message) throws IOException {
-    getNotebookService().listNotesInfo(false, getServiceContext(message),
+  public void listNotesInfo(NotebookSocket conn, ServiceContext context) throws IOException {
+    getNotebookService().listNotesInfo(false, context,
         new WebSocketServiceCallback<List<NoteInfo>>(conn) {
           @Override
           public void onSuccess(List<NoteInfo> notesInfo,
@@ -813,12 +815,12 @@ public class NotebookServer extends WebSocketServlet
     return true;
   }
 
-  private void getNote(NotebookSocket conn, Message fromMessage) throws IOException {
+  private void getNote(NotebookSocket conn, ServiceContext context, Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
     if (noteId == null) {
       return;
     }
-    getNotebookService().getNote(noteId, getServiceContext(fromMessage),
+    getNotebookService().getNote(noteId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -859,9 +861,9 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void getHomeNote(NotebookSocket conn,
-                           Message fromMessage) throws IOException {
+                           ServiceContext context) throws IOException {
 
-    getNotebookService().getHomeNote(getServiceContext(fromMessage),
+    getNotebookService().getHomeNote(context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -879,6 +881,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void updateNote(NotebookSocket conn,
+                          ServiceContext context,
                           Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
     String name = (String) fromMessage.get("name");
@@ -890,7 +893,7 @@ public class NotebookServer extends WebSocketServlet
       return;
     }
 
-    getNotebookService().updateNote(noteId, name, config, getServiceContext(fromMessage),
+    getNotebookService().updateNote(noteId, name, config, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -903,13 +906,14 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void updatePersonalizedMode(NotebookSocket conn,
+                                      ServiceContext context,
                                       Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
     String personalized = (String) fromMessage.get("personalized");
     boolean isPersonalized = personalized.equals("true") ? true : false;
 
-    getNotebookService().updatePersonalizedMode(noteId, isPersonalized,
-        getServiceContext(fromMessage), new WebSocketServiceCallback<Note>(conn) {
+    getNotebookService().updatePersonalizedMode(noteId, isPersonalized, context,
+            new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
             super.onSuccess(note, context);
@@ -919,6 +923,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void renameNote(NotebookSocket conn,
+                          ServiceContext context,
                           Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
     String name = (String) fromMessage.get("name");
@@ -929,7 +934,7 @@ public class NotebookServer extends WebSocketServlet
     if (noteId == null) {
       return;
     }
-    getNotebookService().renameNote(noteId, name, isRelativePath, getServiceContext(fromMessage),
+    getNotebookService().renameNote(noteId, name, isRelativePath, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -941,10 +946,11 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void renameFolder(NotebookSocket conn,
+                            ServiceContext context,
                             Message fromMessage) throws IOException {
     String oldFolderId = (String) fromMessage.get("id");
     String newFolderId = (String) fromMessage.get("name");
-    getNotebookService().renameFolder(oldFolderId, newFolderId, getServiceContext(fromMessage),
+    getNotebookService().renameFolder(oldFolderId, newFolderId, context,
         new WebSocketServiceCallback<List<NoteInfo>>(conn) {
           @Override
           public void onSuccess(List<NoteInfo> result, ServiceContext context) throws IOException {
@@ -955,12 +961,13 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void createNote(NotebookSocket conn,
+                          ServiceContext context,
                           Message message) throws IOException {
 
     String noteName = (String) message.get("name");
     String defaultInterpreterGroup = (String) message.get("defaultInterpreterGroup");
 
-    getNotebookService().createNote(noteName, defaultInterpreterGroup, true, getServiceContext(message),
+    getNotebookService().createNote(noteName, defaultInterpreterGroup, true, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -980,9 +987,10 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void deleteNote(NotebookSocket conn,
+                          ServiceContext context,
                           Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
-    getNotebookService().removeNote(noteId, getServiceContext(fromMessage),
+    getNotebookService().removeNote(noteId, context,
         new WebSocketServiceCallback<String>(conn) {
           @Override
           public void onSuccess(String message, ServiceContext context) throws IOException {
@@ -994,11 +1002,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void removeFolder(NotebookSocket conn,
+                            ServiceContext context,
                             Message fromMessage) throws IOException {
 
     String folderPath = (String) fromMessage.get("id");
     folderPath = "/" + folderPath;
-    getNotebookService().removeFolder(folderPath, getServiceContext(fromMessage),
+    getNotebookService().removeFolder(folderPath, context,
         new WebSocketServiceCallback<List<NoteInfo>>(conn) {
           @Override
           public void onSuccess(List<NoteInfo> notesInfo,
@@ -1013,9 +1022,10 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void moveNoteToTrash(NotebookSocket conn,
+                               ServiceContext context,
                                Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
-    getNotebookService().moveNoteToTrash(noteId, getServiceContext(fromMessage),
+    getNotebookService().moveNoteToTrash(noteId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1027,11 +1037,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void moveFolderToTrash(NotebookSocket conn,
+                                 ServiceContext context,
                                  Message fromMessage)
       throws IOException {
 
     String folderPath = (String) fromMessage.get("id");
-    getNotebookService().moveFolderToTrash(folderPath, getServiceContext(fromMessage),
+    getNotebookService().moveFolderToTrash(folderPath, context,
         new WebSocketServiceCallback<Void>(conn) {
           @Override
           public void onSuccess(Void result, ServiceContext context) throws IOException {
@@ -1043,9 +1054,10 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void restoreNote(NotebookSocket conn,
+                           ServiceContext context,
                            Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("id");
-    getNotebookService().restoreNote(noteId, getServiceContext(fromMessage),
+    getNotebookService().restoreNote(noteId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1058,10 +1070,11 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void restoreFolder(NotebookSocket conn,
+                             ServiceContext context,
                              Message fromMessage) throws IOException {
     String folderPath = (String) fromMessage.get("id");
     folderPath = "/" + folderPath;
-    getNotebookService().restoreFolder(folderPath, getServiceContext(fromMessage),
+    getNotebookService().restoreFolder(folderPath, context,
         new WebSocketServiceCallback(conn) {
           @Override
           public void onSuccess(Object result, ServiceContext context) throws IOException {
@@ -1072,8 +1085,9 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void restoreAll(NotebookSocket conn,
+                          ServiceContext context,
                           Message fromMessage) throws IOException {
-    getNotebookService().restoreAll(getServiceContext(fromMessage),
+    getNotebookService().restoreAll(context,
         new WebSocketServiceCallback(conn) {
           @Override
           public void onSuccess(Object result, ServiceContext context) throws IOException {
@@ -1084,8 +1098,8 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void emptyTrash(NotebookSocket conn,
-                          Message fromMessage) throws IOException {
-    getNotebookService().emptyTrash(getServiceContext(fromMessage),
+                          ServiceContext context) throws IOException {
+    getNotebookService().emptyTrash(context,
         new WebSocketServiceCallback(conn) {
           @Override
           public void onSuccess(Object result, ServiceContext context) throws IOException {
@@ -1096,6 +1110,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void updateParagraph(NotebookSocket conn,
+                               ServiceContext context,
                                Message fromMessage) throws IOException {
     String paragraphId = (String) fromMessage.get("id");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
@@ -1107,8 +1122,7 @@ public class NotebookServer extends WebSocketServlet
     Map<String, Object> params = (Map<String, Object>) fromMessage.get("params");
     Map<String, Object> config = (Map<String, Object>) fromMessage.get("config");
 
-    getNotebookService().updateParagraph(noteId, paragraphId, title, text, params, config,
-        getServiceContext(fromMessage),
+    getNotebookService().updateParagraph(noteId, paragraphId, title, text, params, config, context,
         new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
@@ -1125,6 +1139,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void patchParagraph(NotebookSocket conn,
+                              ServiceContext context,
                               Message fromMessage) throws IOException {
     if (!collaborativeModeEnable) {
       return;
@@ -1147,8 +1162,7 @@ public class NotebookServer extends WebSocketServlet
       return;
     }
 
-    getNotebookService().patchParagraph(noteId, paragraphId, patchText,
-        getServiceContext(fromMessage),
+    getNotebookService().patchParagraph(noteId, paragraphId, patchText, context,
         new WebSocketServiceCallback<String>(conn) {
           @Override
           public void onSuccess(String result, ServiceContext context) throws IOException {
@@ -1161,10 +1175,11 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void cloneNote(NotebookSocket conn,
+                         ServiceContext context,
                          Message fromMessage) throws IOException {
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
     String name = (String) fromMessage.get("name");
-    getNotebookService().cloneNote(noteId, name, getServiceContext(fromMessage),
+    getNotebookService().cloneNote(noteId, name, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note newNote, ServiceContext context) throws IOException {
@@ -1177,9 +1192,10 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void clearAllParagraphOutput(NotebookSocket conn,
+                                       ServiceContext context,
                                        Message fromMessage) throws IOException {
     final String noteId = (String) fromMessage.get("id");
-    getNotebookService().clearAllParagraphOutput(noteId, getServiceContext(fromMessage),
+    getNotebookService().clearAllParagraphOutput(noteId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1202,7 +1218,7 @@ public class NotebookServer extends WebSocketServlet
     }
   }
 
-  protected Note importNote(NotebookSocket conn, Message fromMessage) throws IOException {
+  protected Note importNote(NotebookSocket conn, ServiceContext context, Message fromMessage) throws IOException {
     String noteJson = null;
     String noteName = (String) ((Map) fromMessage.get("note")).get("name");
     // Checking whether the notebook data is from a Jupyter or a Zeppelin Notebook.
@@ -1213,7 +1229,7 @@ public class NotebookServer extends WebSocketServlet
       noteJson = new JupyterUtil().getJson(
               gson.toJson(fromMessage.get("note")), IdHashes.generateId(), "%python", "%md");
     }
-    Note note = getNotebookService().importNote(noteName, noteJson, getServiceContext(fromMessage),
+    Note note = getNotebookService().importNote(noteName, noteJson, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1232,11 +1248,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void removeParagraph(NotebookSocket conn,
+                               ServiceContext context,
                                Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
     getNotebookService().removeParagraph(noteId, paragraphId,
-        getServiceContext(fromMessage), new WebSocketServiceCallback<Paragraph>(conn) {
+        context, new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
             super.onSuccess(p, context);
@@ -1247,10 +1264,11 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void clearParagraphOutput(NotebookSocket conn,
+                                    ServiceContext context,
                                     Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
-    getNotebookService().clearParagraphOutput(noteId, paragraphId, getServiceContext(fromMessage),
+    getNotebookService().clearParagraphOutput(noteId, paragraphId, context,
         new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
@@ -1265,13 +1283,13 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void completion(NotebookSocket conn,
+                          ServiceContext context,
                           Message fromMessage) throws IOException {
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
     String paragraphId = (String) fromMessage.get("id");
     String buffer = (String) fromMessage.get("buf");
     int cursor = (int) Double.parseDouble(fromMessage.get("cursor").toString());
-    getNotebookService().completion(noteId, paragraphId, buffer, cursor,
-        getServiceContext(fromMessage),
+    getNotebookService().completion(noteId, paragraphId, buffer, cursor, context,
         new WebSocketServiceCallback<List<InterpreterCompletion>>(conn) {
           @Override
           public void onSuccess(List<InterpreterCompletion> completions, ServiceContext context)
@@ -1300,6 +1318,7 @@ public class NotebookServer extends WebSocketServlet
    * @param fromMessage the message.
    */
   private void angularObjectUpdated(NotebookSocket conn,
+                                    ServiceContext context,
                                     Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String paragraphId = (String) fromMessage.get("paragraphId");
@@ -1309,7 +1328,7 @@ public class NotebookServer extends WebSocketServlet
     String user = fromMessage.principal;
 
     getNotebookService().updateAngularObject(noteId, paragraphId, interpreterGroupId,
-        varName, varValue, getServiceContext(fromMessage),
+        varName, varValue, context,
         new WebSocketServiceCallback<AngularObject>(conn) {
           @Override
           public void onSuccess(AngularObject ao, ServiceContext context) throws IOException {
@@ -1419,12 +1438,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void moveParagraph(NotebookSocket conn,
+                             ServiceContext context,
                              Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");
     final int newIndex = (int) Double.parseDouble(fromMessage.get("index").toString());
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
-    getNotebookService().moveParagraph(noteId, paragraphId, newIndex,
-        getServiceContext(fromMessage),
+    getNotebookService().moveParagraph(noteId, paragraphId, newIndex, context,
         new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph result, ServiceContext context) throws IOException {
@@ -1436,6 +1455,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private String insertParagraph(NotebookSocket conn,
+                                 ServiceContext context,
                                  Message fromMessage) throws IOException {
     final int index = (int) Double.parseDouble(fromMessage.get("index").toString());
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
@@ -1446,8 +1466,7 @@ public class NotebookServer extends WebSocketServlet
       config = new HashMap<>();
     }
 
-    Paragraph newPara = getNotebookService().insertParagraph(noteId, index, config,
-        getServiceContext(fromMessage),
+    Paragraph newPara = getNotebookService().insertParagraph(noteId, index, config, context,
         new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
@@ -1460,25 +1479,27 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void copyParagraph(NotebookSocket conn,
+                             ServiceContext context,
                              Message fromMessage) throws IOException {
-    String newParaId = insertParagraph(conn, fromMessage);
+    String newParaId = insertParagraph(conn, context, fromMessage);
 
     if (newParaId == null) {
       return;
     }
     fromMessage.put("id", newParaId);
 
-    updateParagraph(conn, fromMessage);
+    updateParagraph(conn, context, fromMessage);
   }
 
-  private void cancelParagraph(NotebookSocket conn, Message fromMessage) throws IOException {
+  private void cancelParagraph(NotebookSocket conn, ServiceContext context, Message fromMessage) throws IOException {
     final String paragraphId = (String) fromMessage.get("id");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
-    getNotebookService().cancelParagraph(noteId, paragraphId, getServiceContext(fromMessage),
+    getNotebookService().cancelParagraph(noteId, paragraphId, context,
         new WebSocketServiceCallback<>(conn));
   }
 
   private void runAllParagraphs(NotebookSocket conn,
+                                ServiceContext context,
                                 Message fromMessage) throws IOException {
     final String noteId = (String) fromMessage.get("noteId");
     List<Map<String, Object>> paragraphs =
@@ -1488,11 +1509,11 @@ public class NotebookServer extends WebSocketServlet
 
     executorService.submit(() -> {
       try {
-        if (!getNotebookService().runAllParagraphs(noteId, paragraphs, getServiceContext(fromMessage),
+        if (!getNotebookService().runAllParagraphs(noteId, paragraphs, context,
                 new WebSocketServiceCallback<Paragraph>(conn))) {
           // If one paragraph fails, we need to broadcast paragraph states to the client,
           // or paragraphs not run will stay in PENDING state.
-          Note note = getNotebookService().getNote(noteId, getServiceContext(fromMessage), new SimpleServiceCallback());
+          Note note = getNotebookService().getNote(noteId, context, new SimpleServiceCallback());
           if (note != null) {
             for (Paragraph p : note.getParagraphs()) {
               broadcastParagraph(note, p, null);
@@ -1506,11 +1527,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void broadcastSpellExecution(NotebookSocket conn,
+                                       ServiceContext context,
                                        Message fromMessage) throws IOException {
 
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
     getNotebookService().spell(noteId, fromMessage,
-        getServiceContext(fromMessage), new WebSocketServiceCallback<Paragraph>(conn) {
+        context, new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
             super.onSuccess(p, context);
@@ -1522,6 +1544,7 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void runParagraph(NotebookSocket conn,
+                            ServiceContext context,
                             Message fromMessage) throws IOException {
     String paragraphId = (String) fromMessage.get("id");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
@@ -1530,7 +1553,7 @@ public class NotebookServer extends WebSocketServlet
     Map<String, Object> params = (Map<String, Object>) fromMessage.get("params");
     Map<String, Object> config = (Map<String, Object>) fromMessage.get("config");
     getNotebookService().runParagraph(noteId, paragraphId, title, text, params, config, null,
-        false, false, getServiceContext(fromMessage),
+        false, false, context,
         new WebSocketServiceCallback<Paragraph>(conn) {
           @Override
           public void onSuccess(Paragraph p, ServiceContext context) throws IOException {
@@ -1554,9 +1577,10 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void sendAllConfigurations(NotebookSocket conn,
+                                     ServiceContext context,
                                      Message message) throws IOException {
 
-    getConfigurationService().getAllProperties(getServiceContext(message),
+    getConfigurationService().getAllProperties(context,
         new WebSocketServiceCallback<Map<String, String>>(conn) {
           @Override
           public void onSuccess(Map<String, String> properties,
@@ -1569,12 +1593,14 @@ public class NotebookServer extends WebSocketServlet
         });
   }
 
-  private void checkpointNote(NotebookSocket conn, Message fromMessage)
+  private void checkpointNote(NotebookSocket conn,
+                              ServiceContext context,
+                              Message fromMessage)
       throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String commitMessage = (String) fromMessage.get("commitMessage");
 
-    getNotebookService().checkpointNote(noteId, commitMessage, getServiceContext(fromMessage),
+    getNotebookService().checkpointNote(noteId, commitMessage, context,
         new WebSocketServiceCallback<Revision>(conn) {
           @Override
           public void onSuccess(Revision revision, ServiceContext context) throws IOException {
@@ -1595,10 +1621,12 @@ public class NotebookServer extends WebSocketServlet
         });
   }
 
-  private void listRevisionHistory(NotebookSocket conn, Message fromMessage)
+  private void listRevisionHistory(NotebookSocket conn,
+                                   ServiceContext context,
+                                   Message fromMessage)
       throws IOException {
     String noteId = (String) fromMessage.get("noteId");
-    getNotebookService().listRevisionHistory(noteId, getServiceContext(fromMessage),
+    getNotebookService().listRevisionHistory(noteId, context,
         new WebSocketServiceCallback<List<Revision>>(conn) {
           @Override
           public void onSuccess(List<Revision> revisions, ServiceContext context)
@@ -1611,10 +1639,11 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void setNoteRevision(NotebookSocket conn,
+                               ServiceContext context,
                                Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String revisionId = (String) fromMessage.get("revisionId");
-    getNotebookService().setNoteRevision(noteId, revisionId, getServiceContext(fromMessage),
+    getNotebookService().setNoteRevision(noteId, revisionId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1626,11 +1655,13 @@ public class NotebookServer extends WebSocketServlet
         });
   }
 
-  private void getNoteByRevision(NotebookSocket conn, Message fromMessage)
+  private void getNoteByRevision(NotebookSocket conn,
+                                 ServiceContext context,
+                                 Message fromMessage)
       throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String revisionId = (String) fromMessage.get("revisionId");
-    getNotebookService().getNotebyRevision(noteId, revisionId, getServiceContext(fromMessage),
+    getNotebookService().getNotebyRevision(noteId, revisionId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -1643,12 +1674,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void getNoteByRevisionForCompare(NotebookSocket conn,
+                                           ServiceContext context,
                                            Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String revisionId = (String) fromMessage.get("revisionId");
     String position = (String) fromMessage.get("position");
-    getNotebookService().getNoteByRevisionForCompare(noteId, revisionId,
-        getServiceContext(fromMessage),
+    getNotebookService().getNoteByRevisionForCompare(noteId, revisionId, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -2082,13 +2113,14 @@ public class NotebookServer extends WebSocketServlet
     }
   }
 
-  private void getEditorSetting(NotebookSocket conn, Message fromMessage) throws IOException {
+  private void getEditorSetting(NotebookSocket conn,
+                                ServiceContext context,
+                                Message fromMessage) throws IOException {
     String paragraphId = (String) fromMessage.get("paragraphId");
     String paragraphText = (String) fromMessage.get("paragraphText");
     String noteId = getConnectionManager().getAssociatedNoteId(conn);
 
-    getNotebookService().getEditorSetting(noteId, paragraphText,
-        getServiceContext(fromMessage),
+    getNotebookService().getEditorSetting(noteId, paragraphText, context,
         new WebSocketServiceCallback<Map<String, Object>>(conn) {
           @Override
           public void onSuccess(Map<String, Object> settings,
@@ -2107,9 +2139,10 @@ public class NotebookServer extends WebSocketServlet
         });
   }
 
-  private void getInterpreterSettings(NotebookSocket conn, Message message)
+  private void getInterpreterSettings(NotebookSocket conn,
+                                      ServiceContext context,
+                                      Message message)
       throws IOException {
-    ServiceContext context = getServiceContext(message);
     List<InterpreterSetting> allSettings = getNotebook().getInterpreterSettingManager().get();
     List<InterpreterSetting> result = new ArrayList<>();
     for (InterpreterSetting setting : allSettings) {
@@ -2197,11 +2230,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void saveNoteForms(NotebookSocket conn,
+                             ServiceContext context,
                              Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     Map<String, Object> noteParams = (Map<String, Object>) fromMessage.get("noteParams");
 
-    getNotebookService().saveNoteForms(noteId, noteParams, getServiceContext(fromMessage),
+    getNotebookService().saveNoteForms(noteId, noteParams, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -2211,11 +2245,12 @@ public class NotebookServer extends WebSocketServlet
   }
 
   private void removeNoteForms(NotebookSocket conn,
+                               ServiceContext context,
                                Message fromMessage) throws IOException {
     String noteId = (String) fromMessage.get("noteId");
     String formName = (String) fromMessage.get("formName");
 
-    getNotebookService().removeNoteForms(noteId, formName, getServiceContext(fromMessage),
+    getNotebookService().removeNoteForms(noteId, formName, context,
         new WebSocketServiceCallback<Note>(conn) {
           @Override
           public void onSuccess(Note note, ServiceContext context) throws IOException {
@@ -2236,19 +2271,12 @@ public class NotebookServer extends WebSocketServlet
     getConnectionManager().broadcast(m);
   }
 
-  private ServiceContext getServiceContext(Message message) {
+  private ServiceContext getServiceContext(TicketContainer.Entry ticketEntry) {
     AuthenticationInfo authInfo =
-        new AuthenticationInfo(message.principal, message.roles, message.ticket);
+        new AuthenticationInfo(ticketEntry.getPrincipal(), ticketEntry.getRoles(), ticketEntry.getTicket());
     Set<String> userAndRoles = new HashSet<>();
-    userAndRoles.add(message.principal);
-    if (message.roles != null && !message.roles.equals("")) {
-      HashSet<String> roles =
-          gson.fromJson(message.roles, new TypeToken<HashSet<String>>() {
-          }.getType());
-      if (roles != null) {
-        userAndRoles.addAll(roles);
-      }
-    }
+    userAndRoles.add(authInfo.getUser());
+    userAndRoles.addAll(authInfo.getRoles());
     return new ServiceContext(authInfo, userAndRoles);
   }
 
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
index 636cb47..aa3fd8f 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java
@@ -67,6 +67,7 @@ import org.apache.zeppelin.rest.AbstractTestRestApi;
 import org.apache.zeppelin.scheduler.Job;
 import org.apache.zeppelin.service.ConfigurationService;
 import org.apache.zeppelin.service.NotebookService;
+import org.apache.zeppelin.service.ServiceContext;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.utils.TestUtils;
 import org.junit.AfterClass;
@@ -432,9 +433,10 @@ public class NotebookServerTest extends AbstractTestRestApi {
         "{}}}}";
     Message messageReceived = notebookServer.deserializeMessage(msg);
     Note note = null;
+    ServiceContext context = new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>());
     try {
       try {
-        note = notebookServer.importNote(null, messageReceived);
+        note = notebookServer.importNote(null, context, messageReceived);
       } catch (NullPointerException e) {
         //broadcastNoteList(); failed nothing to worry.
         LOG.error("Exception in NotebookServerTest while testImportNotebook, failed nothing to " +
@@ -459,9 +461,10 @@ public class NotebookServerTest extends AbstractTestRestApi {
             "{\"note\": " + jupyterNoteJson + "}}";
     Message messageReceived = notebookServer.deserializeMessage(msg);
     Note note = null;
+    ServiceContext context = new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>());
     try {
       try {
-        note = notebookServer.importNote(null, messageReceived);
+        note = notebookServer.importNote(null, context, messageReceived);
       } catch (NullPointerException e) {
         //broadcastNoteList(); failed nothing to worry.
         LOG.error("Exception in NotebookServerTest while testImportJupyterNote, failed nothing to " +
@@ -649,8 +652,9 @@ public class NotebookServerTest extends AbstractTestRestApi {
         "{}}}}";
     Message messageReceived = notebookServer.deserializeMessage(msg);
     Note note = null;
+    ServiceContext context = new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>());
     try {
-      note = notebookServer.importNote(null, messageReceived);
+      note = notebookServer.importNote(null, context, messageReceived);
     } catch (NullPointerException e) {
       //broadcastNoteList(); failed nothing to worry.
       LOG.error("Exception in NotebookServerTest while testImportNotebook, failed nothing to " +
diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/ticket/TicketContainerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/ticket/TicketContainerTest.java
index 02f48f7..6004512 100644
--- a/zeppelin-server/src/test/java/org/apache/zeppelin/ticket/TicketContainerTest.java
+++ b/zeppelin-server/src/test/java/org/apache/zeppelin/ticket/TicketContainerTest.java
@@ -38,8 +38,8 @@ public class TicketContainerTest {
 
   @Test
   public void isValidExistingPrincipal() {
-    String ticket = container.getTicket("someuser1");
-    boolean ok = container.isValid("someuser1", ticket);
+    TicketContainer.Entry ticket = container.getTicketEntry("someuser1", null);
+    boolean ok = container.isValid("someuser1", ticket.getTicket());
     assertTrue(ok);
   }
 
@@ -51,8 +51,8 @@ public class TicketContainerTest {
 
   @Test
   public void isValidunkownTicket() {
-    String ticket = container.getTicket("someuser2");
-    boolean ok = container.isValid("someuser2", ticket + "makeitinvalid");
+    TicketContainer.Entry ticketEntry = container.getTicketEntry("someuser2", null);
+    boolean ok = container.isValid("someuser2", ticketEntry.getTicket() + "makeitinvalid");
     assertFalse(ok);
   }
 }
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClient.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClient.java
index 94262a5..ba49d3b 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClient.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/ZeppelinhubClient.java
@@ -237,7 +237,7 @@ public class ZeppelinhubClient {
     }
     zeppelinMsg.data = (Map<String, Object>) hubMsg.data;
     zeppelinMsg.principal = hubMsg.meta.get("owner");
-    zeppelinMsg.ticket = TicketContainer.instance.getTicket(zeppelinMsg.principal);
+    zeppelinMsg.ticket = TicketContainer.instance.getTicketEntry(zeppelinMsg.principal, null).getTicket();
     Client client = Client.getInstance();
     if (client == null) {
       LOGGER.warn("Base client isn't initialized, returning");
@@ -271,7 +271,7 @@ public class ZeppelinhubClient {
         zeppelinMsg.data = gson.fromJson(paragraphs.getString(i),
             new TypeToken<Map<String, Object>>(){}.getType());
         zeppelinMsg.principal = principal;
-        zeppelinMsg.ticket = TicketContainer.instance.getTicket(principal);
+        zeppelinMsg.ticket = TicketContainer.instance.getTicketEntry(principal, null).getTicket();
         client.relayToZeppelin(zeppelinMsg, noteId);
         LOGGER.info("\nSending RUN_PARAGRAPH message to Zeppelin ");
       }
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/listener/WatcherWebsocket.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/listener/WatcherWebsocket.java
index 2a6458d..a649755 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/listener/WatcherWebsocket.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/repo/zeppelinhub/websocket/listener/WatcherWebsocket.java
@@ -55,7 +55,7 @@ public class WatcherWebsocket implements WebSocketListener {
     this.connection = session;
     Message watcherMsg = new Message(OP.WATCHER);
     watcherMsg.principal = watcherPrincipal;
-    watcherMsg.ticket = TicketContainer.instance.getTicket(watcherPrincipal);
+    watcherMsg.ticket = TicketContainer.instance.getTicketEntry(watcherPrincipal, null).getTicket();
     session.getRemote().sendStringByFuture(watcherMsg.toJson());
   }
 
diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/ticket/TicketContainer.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/ticket/TicketContainer.java
index 8c4b170..819b687 100644
--- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/ticket/TicketContainer.java
+++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/ticket/TicketContainer.java
@@ -18,9 +18,13 @@
 package org.apache.zeppelin.ticket;
 
 import java.util.Calendar;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
+
+import com.google.common.collect.Sets;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,15 +39,34 @@ public class TicketContainer {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(TicketContainer.class);
 
-  private static class Entry {
-    public final String ticket;
+  public static final Entry ANONYMOUS_ENTRY = new Entry("anonymous", "anonymous", Sets.newHashSet());
+
+  public static class Entry {
+    private final String ticket;
+    private final String principal;
+    private final Set<String> roles;
+
     // lastAccessTime still unused
     public final long lastAccessTime;
 
-    Entry(String ticket) {
+    Entry(String ticket, String principal, Set<String> roles) {
       this.ticket = ticket;
+      this.principal = principal;
+      this.roles = roles;
       this.lastAccessTime = Calendar.getInstance().getTimeInMillis();
     }
+
+    public String getTicket() {
+      return ticket;
+    }
+
+    public String getPrincipal() {
+      return principal;
+    }
+
+    public Set<String> getRoles() {
+      return roles;
+    }
   }
 
   private Map<String, Entry> sessions = new ConcurrentHashMap<>();
@@ -69,7 +92,22 @@ public class TicketContainer {
    * @param principal
    * @return
    */
-  public synchronized String getTicket(String principal) {
+  public synchronized Entry getTicketEntry(String principal, Set<String> roles) {
+    Entry entry = sessions.get(principal);
+    if (entry == null) {
+      String ticket;
+      if (principal.equals("anonymous")) {
+        ticket = "anonymous";
+      } else {
+        ticket = UUID.randomUUID().toString();
+      }
+      entry = new Entry(ticket, principal, roles);
+      sessions.put(principal, entry);
+    }
+    return entry;
+  }
+
+  public synchronized String getTicket(String principal, Set<String> roles) {
     Entry entry = sessions.get(principal);
     String ticket;
     if (entry == null) {
@@ -80,11 +118,18 @@ public class TicketContainer {
     } else {
       ticket = entry.ticket;
     }
-    entry = new Entry(ticket);
+    entry = new Entry(ticket, principal, roles);
     sessions.put(principal, entry);
     return ticket;
   }
 
+  public Entry getTicketEntry(String ticket) {
+    if ("anonymous".equals(ticket)) {
+      return ANONYMOUS_ENTRY;
+    }
+    return sessions.get(ticket);
+  }
+
   /**
    * Remove ticket from session cache.
    * @param principal